2 Commits
3.2 ... 3.1c

Author SHA1 Message Date
Nicholas Marriott
25cae5d86f 3.1c. 2020-10-30 12:11:02 +00:00
nicm
d0ad34e94d Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments. Reported by Sergey
Nizovtsev.
2020-10-30 12:09:52 +00:00
165 changed files with 8345 additions and 23439 deletions

14
.github/README.md vendored
View File

@@ -14,17 +14,8 @@ page](https://github.com/libevent/libevent/releases/latest).
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
from [this page](https://invisible-mirror.net/archives/ncurses/). from [this page](https://invisible-mirror.net/archives/ncurses/).
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
## Installation ## Installation
### Binary packages
Some platforms provide binary packages for tmux, although these are sometimes
out of date. Examples are listed on
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From release tarball ### From release tarball
To build and install tmux from a release tarball, use: To build and install tmux from a release tarball, use:
@@ -37,9 +28,6 @@ sudo make install
tmux can use the utempter library to update utmp(5), if it is installed - run tmux can use the utempter library to update utmp(5), if it is installed - run
configure with `--enable-utempter` to enable this. configure with `--enable-utempter` to enable this.
For more detailed instructions on building and installing tmux, see
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From version control ### From version control
To get and build the latest from version control - note that this requires To get and build the latest from version control - note that this requires
@@ -81,7 +69,7 @@ And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with `-v` or `-vv` to generate server and client log For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory. files in the current directory.
## Support ## Support

2
.github/lock.yml vendored
View File

@@ -1,4 +1,4 @@
daysUntilLock: 30 daysUntilLock: 180
skipCreatedBefore: false skipCreatedBefore: false
exemptLabels: [] exemptLabels: []
lockLabel: false lockLabel: false

View File

@@ -1,24 +0,0 @@
#!/bin/sh
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update -qq
sudo apt-get -y install bison \
autotools-dev \
libncurses5-dev \
libevent-dev \
pkg-config \
libutempter-dev \
build-essential
if [ "$BUILD" = "musl" -o "$BUILD" = "musl-static" ]; then
sudo apt-get -y install musl-dev \
musl-tools
fi
fi
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sudo pkg install -y \
automake \
libevent \
pkgconf
fi

View File

@@ -1,38 +0,0 @@
#!/bin/sh
BUILD=$PWD/build
LIBEVENT=https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stab\
le.tar.gz
NCURSES=https://ftp.gnu.org/gnu/ncurses/ncurses-6.2.tar.gz
wget -4q $LIBEVENT || exit 1
tar -zxf libevent-*.tar.gz || exit 1
(cd libevent-*/ &&
./configure --prefix=$BUILD \
--enable-shared \
--disable-libevent-regress \
--disable-samples &&
make && make install) || exit 1
wget -4q $NCURSES || exit 1
tar -zxf ncurses-*.tar.gz || exit 1
(cd ncurses-*/ &&
CPPFLAGS=-P ./configure --prefix=$BUILD \
--with-shared \
--with-termlib \
--without-ada \
--without-cxx \
--without-manpages \
--without-progs \
--without-tests \
--without-tack \
--disable-database \
--enable-termcap \
--enable-pc-files \
--with-pkg-config-libdir=$BUILD/lib/pkgconfig &&
make && make install) || exit 1
sh autogen.sh || exit 1
PKG_CONFIG_PATH=$BUILD/lib/pkgconfig ./configure --prefix=$BUILD "$@"
make && make install || (cat config.log; exit 1)

View File

@@ -1,25 +0,0 @@
#!/bin/sh
sh autogen.sh || exit 1
case "$BUILD" in
static)
./configure --enable-static || exit 1
exec make
;;
all)
sh $(dirname $0)/build-all.sh
exec make
;;
musl)
CC=musl-gcc sh $(dirname $0)/build-all.sh
exec make
;;
musl-static)
CC=musl-gcc sh $(dirname $0)/build-all.sh --enable-static
exec make
;;
*)
./configure || exit 1
exec make
;;
esac

2
.gitignore vendored
View File

@@ -19,5 +19,3 @@ configure
tmux.1.* tmux.1.*
*.dSYM *.dSYM
cmd-parse.c cmd-parse.c
fuzz/*-fuzzer
.dirstamp

View File

@@ -1,88 +1,16 @@
language: c language: c
os: os:
- linux - linux
- freebsd - osx
- osx
compiler: compiler:
- gcc - gcc
- clang - clang
arch:
- amd64
- arm64
env:
- BUILD=
- BUILD=static
- BUILD=all
- BUILD=musl
- BUILD=musl-static
jobs:
exclude:
# Static builds are broken on OS X (by Apple)
- os: osx
compiler: gcc
env: BUILD=static
- os: osx
compiler: clang
env: BUILD=static
# No musl on FreeBSD
- os: freebsd
compiler: gcc
env: BUILD=musl
- os: freebsd
compiler: clang
env: BUILD=musl
- os: freebsd
compiler: gcc
env: BUILD=musl-static
- os: freebsd
compiler: clang
env: BUILD=musl-static
# No musl on OS X
- os: osx
compiler: gcc
env: BUILD=musl
- os: osx
compiler: clang
env: BUILD=musl
- os: osx
compiler: gcc
env: BUILD=musl-static
- os: osx
compiler: clang
env: BUILD=musl-static
# arm64 doesn't link ncurses
- os: linux
compiler: gcc
arch: arm64
env: BUILD=all
- os: linux
compiler: clang
arch: arm64
env: BUILD=all
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl-static
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl-static
before_install: before_install:
- sh .github/travis/before-install.sh - 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: script:
- sh .github/travis/build.sh - ./autogen.sh && ./configure && make

373
CHANGES
View File

@@ -1,377 +1,6 @@
CHANGES FROM 3.1c TO 3.2
* Add a flag to disable keys to close a message.
* Permit shortcut keys in buffer, client, tree modes to be configured with a
format (-K flag to choose-buffer, choose-client, choose-tree).
* Add a current_file format for the config file being parsed.
* When display-message used in config file, show the message after the config
file finishes.
* Add client-detached notification in control mode.
* Improve performance of format evaluation.
* Make jump command support UTF-8 in copy mode.
* Support X11 colour names and other colour formats for OSC 10 and 11.
* Add "pipe" variants of "copy-pipe" commands which do not copy.
* Include "focused" in client flags.
* Send Unicode directional isolate characters around horizontal pane borders if
the terminal supports UTF-8 and an extension terminfo(5) capability "Bidi" is
present.
* Add a -S flag to new-window to make it select the existing window if one
with the given name already exists rather than failing with an error.
* Addd a format modifier to check if a window or session name exists (N/w or
N/s).
* Add compat clock_gettime for older macOS.
* Add a no-detached choice to detach-on-destroy which detaches only if there
are no other detached sessions to switch to.
* Add rectangle-on and rectangle-off copy mode commands.
* Change so that window_flags escapes # automatically. A new format
window_raw_flags contains the old unescaped version.
* Add -N flag to never start server even if command would normally do so.
* With incremental search, start empty and only repeat the previous search if
the user tries to search again with an empty prompt.
* Add a value for remain-on-exit that only keeps the pane if the program
failed.
* Add a -C flag to run-shell to use a tmux command rather than a shell command.
* Do not list user options with show-hooks.
* Remove current match indicator in copy mode which can't work anymore since we
only search the visible region.
* Make synchronize-panes a pane option and add -U flag to set-option to unset
an option on all panes.
* Make replacement of ##s consistent when drawing formats, whether followed by
[ or not. Add a flag (e) to the q: format modifier to double up #s
* Add -N flag to display-panes to ignore keys.
* Change how escaping is processed for formats so that ## and # can be used in
styles.
* Add a 'w' format modifier for string width.
* Add support for Haiku.
* Expand menu and popup -x and -y as formats.
* Add numeric comparisons for formats.
* Fire focus events even when the pane is in a mode.
* Add -O flag to display-menu to not automatically close when all mouse buttons
are released.
* Allow fnmatch(3) wildcards in update-environment.
* Disable nested job expansion so that the result of #() is not expanded again.
* Use the setal capability as well as (tmux's) Setulc.
* Add -q flag to unbind-key to hide errors.
* Allow -N without a command to change or add a note to an existing key.
* Add a -w flag to set- and load-buffer to send to clipboard using OSC 52.
* Add -F to set-environment and source-file.
* Allow colour to be spelt as color in various places.
* Add n: modifier to get length of a format.
* Respond to OSC colour requests if a colour is available.
* Add a -d option to display-message to set delay.
* Add a way for control mode clients to subscribe to a format and be notified
of changes rather than having to poll.
* Add some formats for search in copy mode (search_present, search_match).
* Do not wait on shutdown for commands started with run -b.
* Add -b flags to insert a window before (like the existing -a for after) to
break-pane, move-window, new-window.
* Make paste -p the default for ].
* Add support for pausing a pane when the output buffered for a control mode
client gets too far behind. The pause-after flag with a time is set on the
pane with refresh-client -f and a paused pane may be resumed with
refresh-client -A.
* Allow strings in configuration files to span multiple lines - newlines and
any leading whitespace are removed, as well as any following comments that
couldn't be part of a format. This allows long formats or other strings to be
annotated and indented.
* Instead of using a custom parse function to process {} in configuration
files, treat as a set of statements the same as outside {} and convert back
to a string as the last step. This means the rules are consistent inside and
outside {}, %if and friends work at the right time, and the final result
isn't littered with unnecessary newlines.
* Add support for extended keys - both xterm(1)'s CSI 27 ~ sequence and the
libtickit CSI u sequence are accepted; only the latter is output. tmux will
only attempt to use these if the extended-keys option is on and it can detect
that the terminal outside supports them (or is told it does with the
"extkeys" terminal feature).
* Add an option to set the pane border lines style from a choice of single
lines (ACS or UTF-8), double or heavy (UTF-8), simple (plain ASCII) or number
(the pane numbers). Lines that won't work on a non-UTF-8 terminal are
translated back into ACS when they are output.
* Make focus events update the latest client (like a key press).
* Store UTF-8 characters differently to reduce memory use.
* Fix break-pane -n when only one pane in the window.
* Instead of sending all data to control mode clients as fast as possible, add
a limit of how much data will be sent to the client and try to use it for
panes with some degree of fairness.
* Add an active-pane client flag (set with attach-session -f, new-session -f
or refresh-client -f). This allows a client to have an independent active
pane for interactive use (the window client pane is still used for many
things however).
* Add a mark to copy mode, this is set with the set-mark command (bound to X)
and appears with the entire line shown using copy-mode-mark-style and the
marked character in reverse. The jump-to-mark command (bound to M-x) swaps
the mark and the cursor positions.
* Add a -D flag to make the tmux server run in the foreground and not as a
daemon.
* Do not loop forever in copy mode when search finds an empty match.
* Fix the next-matching-bracket logic when using vi(1) keys.
* Add a customize mode where options may be browsed and changed, includes
adding a brief description of each option. Bound to C-b C by default.
* Change message log (C-b ~) so there is one for the server rather than one per
client and it remains after detach, and make it useful by logging every
command.
* Add M-+ and M-- to tree mode to expand and collapse all.
* Change the existing client flags for control mode to apply for any client,
use the same mechanism for the read-only flag and add an ignore-size flag.
refresh-client -F has become -f (-F stays for backwards compatibility) and
attach-session and switch-client now have -f flags also. A new format
client_flags lists the flags and is shown by list-clients by default.
This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different circumstances.
attach -r and switchc -r remain and set or toggle both flags together.
* Store and restore cursor position when copy mode is resized.
* Export TERM_PROGRAM and TERM_PROGRAM_VERSION like various other terminals.
* Add formats for after hook command arguments: hook_arguments with all the
arguments together; hook_argument_0, hook_argument_1 and so on with
individual arguments; hook_flag_X if flag -X is present; hook_flag_X_0,
hook_flag_X_1 and so on if -X appears multiple times.
* Try to search the entire history first for up to 200 ms so a search count can
be shown. If it takes too long, search the visible text only.
* Use VIS_CSTYLE for paste buffers also (show \012 as \n).
* Change default formats for tree mode, client mode and buffer mode to be more
compact and remove some clutter.
* Add a key (e) in buffer mode to open the buffer in an editor. The buffer
contents is updated when the editor exits.
* Add -e flag for new-session to set environment variables, like the same flag
for new-window.
* Improve search match marking in copy mode. Two new options
copy-mode-match-style and copy-mode-current-match-style to set the style for
matches and for the current match respectively. Also a change so that if a
copy key is pressed with no selection, the current match (if any) is copied.
* Sanitize session names like window names instead of forbidding invalid ones.
* Check if the clear terminfo(5) capability starts with CSI and if so then
assume the terminal is VT100-like, rather than relying on the XT capability.
* Improve command prompt tab completion and add menus both for strings and -t
and -s (when used without a trailing space). command-prompt has additional
flags for only completing a window (-W) and a target (-T), allowing C-b ' to
only show windows and C-b . only targets.
* Change all the style options to string options so they can support formats.
Change pane-border-active-style to use this to change the border colour when
in a mode or with synchronize-panes on. This also implies a few minor changes
to existing behaviour:
- set-option -a with a style option automatically inserts a comma between the
old value and appended text.
- OSC 10 and 11 no longer set the window-style option, instead they store the
colour internally in the pane data and it is used as the default when the
option is evaluated.
- status-fg and -bg now override status-style instead of the option values
being changed.
* Add extension terminfo(5) capabilities for margins and focus reporting.
* Try $XDG_CONFIG_HOME/tmux/tmux.conf as well as ~/.config/tmux/tmux.conf for
configuration file (the search paths are in TMUX_CONF in Makefile.am).
* Remove the DSR 1337 iTerm2 extension and replace by the extended device
attributes sequence (CSI > q) supported by more terminals.
* Add a -s flag to copy-mode to specify a different pane for the source
content. This means it is possible to view two places in a pane's history at
the same time in different panes, or view the history while still using the
pane. Pressing r refreshes the content from the source pane.
* Add an argument to list-commands to show only a single command.
* Change copy mode to make copy of the pane history so it does not need to
freeze the pane.
* Restore pane_current_path format from portable tmux on OpenBSD.
* Wait until the initial command sequence is done before sending a device
attributes request and other bits that prompt a reply from the terminal. This
means that stray relies are not left on the terminal if the command has
attached and then immediately detached and tmux will not be around to receive
them.
* Add a -f filter argument to the list commands like choose-tree.
* Move specific hooks for panes to pane options and windows for window options
rather than all hooks being session options. These hooks are now window options:
window-layout-changed
window-linked
window-pane-changed
window-renamed
window-unlinked
And these now pane options:
pane-died
pane-exited
pane-focus-in
pane-focus-out
pane-mode-changed
pane-set-clipboard
Any existing configurations using these hooks on a session rather than
globally (that is, set-hook or set-option without -g) may need to be changed.
* Show signal names when a process exits with remain-on-exit on platforms which
have a way to get them.
* Start menu with top item selected if no mouse and use mode-style for the
selected item.
* Add a copy-command option and change copy-pipe and friends to pipe to it if
used without arguments, allows all the default copy key bindings to be
changed to pipe with one option rather than needing to change each key
binding individually.
* Tidy up the terminal detection and feature code and add named sets of
terminal features, each of which are defined in one place and map to a
builtin set of terminfo(5) capabilities. Features can be specified based on
TERM with a new terminal-features option or with the -T flag when running
tmux. tmux will also detect a few common terminals from the DA and DSR
responses.
This is intended to make it easier to configure tmux's use of terminfo(5)
even in the presence of outdated ncurses(3) or terminfo(5) databases or for
features which do not yet have a terminfo(5) entry. Instead of having to grok
terminfo(5) capability names and what they should be set to in the
terminal-overrides option, the user can hopefully just give tmux a feature
name and let it do the right thing.
The terminal-overrides option remains both for backwards compatibility and to
allow tweaks of individual capabilities.
* Support mintty's application escape sequence (means tmux doesn't have to
delay to wait for Escape, so no need to reduce escape-time when using
mintty).
* Change so main-pane-width and height can be given as a percentage.
* Support for the iTerm2 synchronized updates feature (allows the terminal to
avoid unnecessary drawing while output is still in progress).
* Make the mouse_word and mouse_line formats work in copy mode and enable the
default pane menu in copy mode.
* Add a -T flag to resize-pane to trim lines below the cursor, moving lines out
of the history.
* Add a way to mark environment variables as "hidden" so they can be used by
tmux (for example in formats) but are not set in the environment for new
panes. set-environment and show-environment have a new -h flag and there is a
new %hidden statement for the configuration file.
* Change default position for display-menu -x and -y to centre rather than top
left.
* Add support for per-client transient popups, similar to menus but which are
connected to an external command (like a pane). These are created with new
command display-popup.
* Change double and triple click bindings so that only one is fired (previously
double click was fired on the way to triple click). Also add default double
and triple click bindings to copy the word or line under the cursor and
change the existing bindings in copy mode to do the same.
* Add a default binding for button 2 to paste.
* Add -d flag to run-shell to delay before running the command and allow it to
run without a command so it just delays.
* Add C-g to cancel command prompt with vi keys as well as emacs, and q in
command mode.
* When the server socket is given with -S, create it with umask 177 instead of
117 (because it may not be in a safe directory like the default directory in
/tmp).
* Add a copy-mode -H flag to hide the position marker in the top right.
* Add number operators for formats (+, -, *, / and m),
CHANGED FROM 3.1b TO 3.1c CHANGED FROM 3.1b TO 3.1c
* Do not write after the end of the array and overwrite the stack when * Fix a stack overflow on colon-separated CSI parsing.
colon-separated SGR sequences contain empty arguments.
CHANGES FROM 3.1a TO 3.1b CHANGES FROM 3.1a TO 3.1b

View File

@@ -12,8 +12,8 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags. # Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ \ AM_CPPFLAGS += @XOPEN_DEFINES@ \
-DTMUX_VERSION='"@VERSION@"' \ -DTMUX_VERSION="\"@VERSION@\"" \
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' -DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\""
# Additional object files. # Additional object files.
LDADD = $(LIBOBJS) LDADD = $(LIBOBJS)
@@ -28,7 +28,7 @@ AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k AM_CFLAGS += -Wno-unused-result
AM_CPPFLAGS += -DDEBUG AM_CPPFLAGS += -DDEBUG
endif endif
AM_CPPFLAGS += -iquote. AM_CPPFLAGS += -iquote.
@@ -58,11 +58,6 @@ if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif endif
# Set flags for Haiku.
if IS_HAIKU
AM_CPPFLAGS += -D_BSD_SOURCE
endif
# List of sources. # List of sources.
dist_tmux_SOURCES = \ dist_tmux_SOURCES = \
alerts.c \ alerts.c \
@@ -141,7 +136,6 @@ dist_tmux_SOURCES = \
file.c \ file.c \
format.c \ format.c \
format-draw.c \ format-draw.c \
grid-reader.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
input-keys.c \ input-keys.c \
@@ -160,7 +154,6 @@ dist_tmux_SOURCES = \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
popup.c \
proc.c \ proc.c \
regsub.c \ regsub.c \
resize.c \ resize.c \
@@ -177,7 +170,6 @@ dist_tmux_SOURCES = \
tmux.c \ tmux.c \
tmux.h \ tmux.h \
tty-acs.c \ tty-acs.c \
tty-features.c \
tty-keys.c \ tty-keys.c \
tty-term.c \ tty-term.c \
tty.c \ tty.c \
@@ -186,11 +178,11 @@ dist_tmux_SOURCES = \
window-client.c \ window-client.c \
window-clock.c \ window-clock.c \
window-copy.c \ window-copy.c \
window-customize.c \
window-tree.c \ window-tree.c \
window.c \ window.c \
xmalloc.c \ xmalloc.c \
xmalloc.h xmalloc.h \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty. # Add compat file for forkpty.
@@ -203,12 +195,6 @@ if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c nodist_tmux_SOURCES += compat/utf8proc.c
endif endif
if NEED_FUZZING
check_PROGRAMS = fuzz/input-fuzzer
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
endif
# Install tmux.1 in the right format. # Install tmux.1 in the right format.
install-exec-hook: install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \ if test x@MANFORMAT@ = xmdoc; then \

3
README
View File

@@ -16,9 +16,6 @@ It also depends on ncurses, available from:
https://invisible-mirror.net/archives/ncurses/ https://invisible-mirror.net/archives/ncurses/
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
* Installation * Installation
To build and install tmux from a release tarball, use: To build and install tmux from a release tarball, use:

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <event.h>
#include <stdlib.h> #include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -199,7 +200,7 @@ alerts_check_bell(struct window *w)
* not check WINLINK_BELL). * not check WINLINK_BELL).
*/ */
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_BELL; wl->flags |= WINLINK_BELL;
server_status_session(s); server_status_session(s);
} }
@@ -235,7 +236,7 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY) if (wl->flags & WINLINK_ACTIVITY)
continue; continue;
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY; wl->flags |= WINLINK_ACTIVITY;
server_status_session(s); server_status_session(s);
} }
@@ -271,7 +272,7 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE) if (wl->flags & WINLINK_SILENCE)
continue; continue;
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE; wl->flags |= WINLINK_SILENCE;
server_status_session(s); server_status_session(s);
} }
@@ -314,12 +315,9 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
tty_putcode(&c->tty, TTYC_BEL); tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF) if (visual == VISUAL_OFF)
continue; continue;
if (c->session->curw == wl) { if (c->session->curw == wl)
status_message_set(c, -1, 1, 0, "%s in current window", status_message_set(c, "%s in current window", type);
type); else
} else { status_message_set(c, "%s in window %d", type, wl->idx);
status_message_set(c, -1, 1, 0, "%s in window %d", type,
wl->idx);
}
} }
} }

View File

@@ -55,11 +55,11 @@ args_cmp(struct args_entry *a1, struct args_entry *a2)
/* Find a flag in the arguments tree. */ /* Find a flag in the arguments tree. */
static struct args_entry * static struct args_entry *
args_find(struct args *args, u_char flag) args_find(struct args *args, u_char ch)
{ {
struct args_entry entry; struct args_entry entry;
entry.flag = flag; entry.flag = ch;
return (RB_FIND(args_tree, &args->tree, &entry)); return (RB_FIND(args_tree, &args->tree, &entry));
} }
@@ -211,35 +211,25 @@ args_print(struct args *args)
char * char *
args_escape(const char *s) args_escape(const char *s)
{ {
static const char dquoted[] = " #';${}"; static const char quoted[] = " #\"';${}";
static const char squoted[] = " \"";
char *escaped, *result; char *escaped, *result;
int flags, quotes = 0; int flags;
if (*s == '\0') {
xasprintf(&result, "''");
return (result);
}
if (s[strcspn(s, dquoted)] != '\0')
quotes = '"';
else if (s[strcspn(s, squoted)] != '\0')
quotes = '\'';
if (*s == '\0')
return (xstrdup(s));
if (s[0] != ' ' && if (s[0] != ' ' &&
s[1] == '\0' && (strchr(quoted, s[0]) != NULL || s[0] == '~') &&
(quotes != 0 || s[0] == '~')) { s[1] == '\0') {
xasprintf(&escaped, "\\%c", s[0]); xasprintf(&escaped, "\\%c", s[0]);
return (escaped); return (escaped);
} }
flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL; flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
if (quotes == '"') if (s[strcspn(s, quoted)] != '\0')
flags |= VIS_DQ; flags |= VIS_DQ;
utf8_stravis(&escaped, s, flags); utf8_stravis(&escaped, s, flags);
if (quotes == '\'') if (flags & VIS_DQ) {
xasprintf(&result, "'%s'", escaped);
else if (quotes == '"') {
if (*escaped == '~') if (*escaped == '~')
xasprintf(&result, "\"\\%s\"", escaped); xasprintf(&result, "\"\\%s\"", escaped);
else else
@@ -256,11 +246,11 @@ args_escape(const char *s)
/* Return if an argument is present. */ /* Return if an argument is present. */
int int
args_has(struct args *args, u_char flag) args_has(struct args *args, u_char ch)
{ {
struct args_entry *entry; struct args_entry *entry;
entry = args_find(args, flag); entry = args_find(args, ch);
if (entry == NULL) if (entry == NULL)
return (0); return (0);
return (entry->count); return (entry->count);
@@ -268,15 +258,15 @@ args_has(struct args *args, u_char flag)
/* Set argument value in the arguments tree. */ /* Set argument value in the arguments tree. */
void void
args_set(struct args *args, u_char flag, const char *s) args_set(struct args *args, u_char ch, const char *s)
{ {
struct args_entry *entry; struct args_entry *entry;
struct args_value *value; struct args_value *value;
entry = args_find(args, flag); entry = args_find(args, ch);
if (entry == NULL) { if (entry == NULL) {
entry = xcalloc(1, sizeof *entry); entry = xcalloc(1, sizeof *entry);
entry->flag = flag; entry->flag = ch;
entry->count = 1; entry->count = 1;
TAILQ_INIT(&entry->values); TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry); RB_INSERT(args_tree, &args->tree, entry);
@@ -292,44 +282,22 @@ args_set(struct args *args, u_char flag, const char *s)
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */
const char * const char *
args_get(struct args *args, u_char flag) args_get(struct args *args, u_char ch)
{ {
struct args_entry *entry; struct args_entry *entry;
if ((entry = args_find(args, flag)) == NULL) if ((entry = args_find(args, ch)) == NULL)
return (NULL);
if (TAILQ_EMPTY(&entry->values))
return (NULL); return (NULL);
return (TAILQ_LAST(&entry->values, args_values)->value); return (TAILQ_LAST(&entry->values, args_values)->value);
} }
/* Get first argument. */
u_char
args_first(struct args *args, struct args_entry **entry)
{
*entry = RB_MIN(args_tree, &args->tree);
if (*entry == NULL)
return (0);
return ((*entry)->flag);
}
/* Get next argument. */
u_char
args_next(struct args_entry **entry)
{
*entry = RB_NEXT(args_tree, &args->tree, *entry);
if (*entry == NULL)
return (0);
return ((*entry)->flag);
}
/* Get first value in argument. */ /* Get first value in argument. */
const char * const char *
args_first_value(struct args *args, u_char flag, struct args_value **value) args_first_value(struct args *args, u_char ch, struct args_value **value)
{ {
struct args_entry *entry; struct args_entry *entry;
if ((entry = args_find(args, flag)) == NULL) if ((entry = args_find(args, ch)) == NULL)
return (NULL); return (NULL);
*value = TAILQ_FIRST(&entry->values); *value = TAILQ_FIRST(&entry->values);
@@ -352,15 +320,15 @@ args_next_value(struct args_value **value)
/* Convert an argument value to a number. */ /* Convert an argument value to a number. */
long long long long
args_strtonum(struct args *args, u_char flag, long long minval, args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
long long maxval, char **cause) char **cause)
{ {
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry; struct args_entry *entry;
struct args_value *value; struct args_value *value;
if ((entry = args_find(args, flag)) == NULL) { if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
@@ -375,60 +343,3 @@ args_strtonum(struct args *args, u_char flag, long long minval,
*cause = NULL; *cause = NULL;
return (ll); return (ll);
} }
/* Convert an argument to a number which may be a percentage. */
long long
args_percentage(struct args *args, u_char flag, long long minval,
long long maxval, long long curval, char **cause)
{
const char *value;
struct args_entry *entry;
if ((entry = args_find(args, flag)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values)->value;
return (args_string_percentage(value, minval, maxval, curval, cause));
}
/* Convert a string to a number which may be a percentage. */
long long
args_string_percentage(const char *value, long long minval, long long maxval,
long long curval, char **cause)
{
const char *errstr;
long long ll;
size_t valuelen = strlen(value);
char *copy;
if (value[valuelen - 1] == '%') {
copy = xstrdup(value);
copy[valuelen - 1] = '\0';
ll = strtonum(copy, 0, 100, &errstr);
free(copy);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
ll = (curval * ll) / 100;
if (ll < minval) {
*cause = xstrdup("too small");
return (0);
}
if (ll > maxval) {
*cause = xstrdup("too large");
return (0);
}
} else {
ll = strtonum(value, minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
}
*cause = NULL;
return (ll);
}

View File

@@ -31,8 +31,7 @@ attributes_tostring(int attr)
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "", (attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "", (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -63,7 +62,6 @@ attributes_fromstring(const char *str)
const char *name; const char *name;
int attr; int attr;
} table[] = { } table[] = {
{ "acs", GRID_ATTR_CHARSET },
{ "bright", GRID_ATTR_BRIGHT }, { "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT }, { "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM }, { "dim", GRID_ATTR_DIM },

93
cfg.c
View File

@@ -27,15 +27,12 @@
#include "tmux.h" #include "tmux.h"
struct client *cfg_client; struct client *cfg_client;
static char *cfg_file;
int cfg_finished; int cfg_finished;
static char **cfg_causes; static char **cfg_causes;
static u_int cfg_ncauses; static u_int cfg_ncauses;
static struct cmdq_item *cfg_item; static struct cmdq_item *cfg_item;
int cfg_quiet = 1;
char **cfg_files;
u_int cfg_nfiles;
static enum cmd_retval static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data) cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{ {
@@ -62,11 +59,52 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
static char *
expand_cfg_file(const char *path, const char *home)
{
char *expanded, *name;
const char *end;
struct environ_entry *value;
if (strncmp(path, "~/", 2) == 0) {
if (home == NULL)
return (NULL);
xasprintf(&expanded, "%s%s", home, path + 1);
return (expanded);
}
if (*path == '$') {
end = strchr(path, '/');
if (end == NULL)
name = xstrdup(path + 1);
else
name = xstrndup(path + 1, end - path - 1);
value = environ_find(global_environ, name);
free(name);
if (value == NULL)
return (NULL);
if (end == NULL)
end = "";
xasprintf(&expanded, "%s%s", value->value, end);
return (expanded);
}
return (xstrdup(path));
}
void void
start_cfg(void) start_cfg(void)
{ {
struct client *c; const char *home = find_home();
u_int i; struct client *c;
char *path, *copy, *next, *expanded;
/* /*
* Configuration files are loaded without a client, so commands are run * Configuration files are loaded without a client, so commands are run
@@ -84,12 +122,21 @@ start_cfg(void)
cmdq_append(c, cfg_item); cmdq_append(c, cfg_item);
} }
for (i = 0; i < cfg_nfiles; i++) { if (cfg_file == NULL) {
if (cfg_quiet) path = copy = xstrdup(TMUX_CONF);
load_cfg(cfg_files[i], c, NULL, CMD_PARSE_QUIET, NULL); while ((next = strsep(&path, ":")) != NULL) {
else expanded = expand_cfg_file(next, home);
load_cfg(cfg_files[i], c, NULL, 0, NULL); if (expanded == NULL) {
} log_debug("couldn't expand %s", next);
continue;
}
log_debug("expanded %s to %s", next, expanded);
load_cfg(expanded, c, NULL, CMD_PARSE_QUIET, NULL);
free(expanded);
}
free(copy);
} else
load_cfg(cfg_file, c, NULL, 0, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
} }
@@ -102,7 +149,6 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmd_parse_input pi; struct cmd_parse_input pi;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct cmdq_item *new_item0; struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL) if (new_item != NULL)
*new_item = NULL; *new_item = NULL;
@@ -136,19 +182,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
return (0); return (0);
} }
if (item != NULL) new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
state = cmdq_copy_state(cmdq_get_state(item));
else
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL) if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0); new_item0 = cmdq_insert_after(item, new_item0);
else else
new_item0 = cmdq_append(NULL, new_item0); new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL) if (new_item != NULL)
*new_item = new_item0; *new_item = new_item0;
@@ -163,7 +202,6 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct cmd_parse_input pi; struct cmd_parse_input pi;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct cmdq_item *new_item0; struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL) if (new_item != NULL)
*new_item = NULL; *new_item = NULL;
@@ -190,19 +228,12 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
return (0); return (0);
} }
if (item != NULL) new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
state = cmdq_copy_state(cmdq_get_state(item));
else
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL) if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0); new_item0 = cmdq_insert_after(item, new_item0);
else else
new_item0 = cmdq_append(NULL, new_item0); new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL) if (new_item != NULL)
*new_item = new_item0; *new_item = new_item0;
@@ -252,7 +283,7 @@ cfg_show_causes(struct session *s)
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL); window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]); window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]); free(cfg_causes[i]);

482
client.c
View File

@@ -18,12 +18,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/file.h> #include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
@@ -34,8 +34,7 @@
static struct tmuxproc *client_proc; static struct tmuxproc *client_proc;
static struct tmuxpeer *client_peer; static struct tmuxpeer *client_peer;
static uint64_t client_flags; static int client_flags;
static int client_suspended;
static enum { static enum {
CLIENT_EXIT_NONE, CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED, CLIENT_EXIT_DETACHED,
@@ -45,13 +44,11 @@ static enum {
CLIENT_EXIT_LOST_SERVER, CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED, CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED, CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE; } client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag; static int client_exitflag;
static int client_exitval; static int client_exitval;
static enum msgtype client_exittype; static enum msgtype client_exittype;
static const char *client_exitsession; static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell; static const char *client_execshell;
static const char *client_execcmd; static const char *client_execcmd;
static int client_attached; static int client_attached;
@@ -59,10 +56,8 @@ static struct client_files client_files = RB_INITIALIZER(&client_files);
static __dead void client_exec(const char *,const char *); static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *); static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *, static int client_connect(struct event_base *, const char *, int);
uint64_t); static void client_send_identify(const char *, const char *);
static void client_send_identify(const char *, const char *,
char **, u_int, const char *, int);
static void client_signal(int); static void client_signal(int);
static void client_dispatch(struct imsg *, void *); static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *); static void client_dispatch_attached(struct imsg *);
@@ -102,7 +97,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */ /* Connect client to server. */
static int static int
client_connect(struct event_base *base, const char *path, uint64_t flags) client_connect(struct event_base *base, const char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
@@ -127,9 +122,7 @@ retry:
log_debug("connect failed: %s", strerror(errno)); log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT) if (errno != ECONNREFUSED && errno != ENOENT)
goto failed; goto failed;
if (flags & CLIENT_NOSTARTSERVER) if (!start_server)
goto failed;
if (~flags & CLIENT_STARTSERVER)
goto failed; goto failed;
close(fd); close(fd);
@@ -161,7 +154,7 @@ retry:
close(lockfd); close(lockfd);
return (-1); return (-1);
} }
fd = server_start(client_proc, flags, base, lockfd, lockfile); fd = server_start(client_proc, base, lockfd, lockfile);
} }
if (locked && lockfd >= 0) { if (locked && lockfd >= 0) {
@@ -213,8 +206,6 @@ client_exit_message(void)
return ("exited"); return ("exited");
case CLIENT_EXIT_SERVER_EXITED: case CLIENT_EXIT_SERVER_EXITED:
return ("server exited"); return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
} }
return ("unknown reason"); return ("unknown reason");
} }
@@ -223,37 +214,51 @@ client_exit_message(void)
static void static void
client_exit(void) client_exit(void)
{ {
if (!file_write_left(&client_files)) struct client_file *cf;
size_t left;
int waiting = 0;
RB_FOREACH (cf, client_files, &client_files) {
if (cf->event == NULL)
continue;
left = EVBUFFER_LENGTH(cf->event->output);
if (left != 0) {
waiting++;
log_debug("file %u %zu bytes left", cf->stream, left);
}
}
if (waiting == 0)
proc_exit(client_proc); proc_exit(client_proc);
} }
/* Client main loop. */ /* Client main loop. */
int int
client_main(struct event_base *base, int argc, char **argv, uint64_t flags, client_main(struct event_base *base, int argc, char **argv, int flags)
int feat)
{ {
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct cmd *cmd;
struct msg_command *data; struct msg_command *data;
int fd, i; int cmdflags, fd, i;
const char *ttynam, *termname, *cwd; const char *ttynam, *cwd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
struct termios tio, saved_tio; struct termios tio, saved_tio;
size_t size, linesize = 0; size_t size;
ssize_t linelen;
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */ /* Set up the initial command. */
cmdflags = 0;
if (shell_command != NULL) { if (shell_command != NULL) {
msg = MSG_SHELL; msg = MSG_SHELL;
flags |= CLIENT_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else if (argc == 0) { } else if (argc == 0) {
msg = MSG_COMMAND; msg = MSG_COMMAND;
flags |= CLIENT_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else { } else {
msg = MSG_COMMAND; msg = MSG_COMMAND;
@@ -264,8 +269,10 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
*/ */
pr = cmd_parse_from_arguments(argc, argv, NULL); pr = cmd_parse_from_arguments(argc, argv, NULL);
if (pr->status == CMD_PARSE_SUCCESS) { if (pr->status == CMD_PARSE_SUCCESS) {
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER)) TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
flags |= CLIENT_STARTSERVER; if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
} else } else
free(pr->error); free(pr->error);
@@ -275,12 +282,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
client_proc = proc_start("client"); client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal); proc_set_signals(client_proc, client_signal);
/* Save the flags. */
client_flags = flags;
log_debug("flags are %#llx", (unsigned long long)client_flags);
/* Initialize the client socket and start the server. */ /* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, client_flags); fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) { if (fd == -1) {
if (errno == ECONNREFUSED) { if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n", fprintf(stderr, "no server running on %s\n",
@@ -298,8 +301,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
cwd = "/"; cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL) if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = ""; ttynam = "";
if ((termname = getenv("TERM")) == NULL)
termname = "";
/* /*
* Drop privileges for client. "proc exec" is needed for -c and for * Drop privileges for client. "proc exec" is needed for -c and for
@@ -315,16 +316,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
NULL) != 0) NULL) != 0)
fatal("pledge failed"); fatal("pledge failed");
/* Load terminfo entry if any. */
if (isatty(STDIN_FILENO) &&
*termname != '\0' &&
tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
&cause) != 0) {
fprintf(stderr, "%s\n", cause);
free(cause);
return (1);
}
/* Free stuff that is not used in the client. */ /* Free stuff that is not used in the client. */
if (ptm_fd != -1) if (ptm_fd != -1)
close(ptm_fd); close(ptm_fd);
@@ -355,8 +346,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
} }
/* Send identify messages. */ /* Send identify messages. */
client_send_identify(ttynam, termname, caps, ncaps, cwd, feat); client_send_identify(ttynam, cwd);
tty_term_free_list(caps, ncaps);
/* Send first command. */ /* Send first command. */
if (msg == MSG_COMMAND) { if (msg == MSG_COMMAND) {
@@ -399,11 +389,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
client_exec(client_execshell, client_execcmd); client_exec(client_execshell, client_execcmd);
} }
/* Restore streams to blocking. */
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
/* Print the exit message, if any, and exit. */ /* Print the exit message, if any, and exit. */
if (client_attached) { if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
@@ -412,65 +397,42 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
ppid = getppid(); ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1) if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP); kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROL) { } else if (client_flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message()); printf("%%exit %s\n", client_exit_message());
else else
printf("%%exit\n"); printf("%%exit\n");
fflush(stdout); printf("\033\\");
if (client_flags & CLIENT_CONTROL_WAITEXIT) { tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
setvbuf(stdin, NULL, _IOLBF, 0);
for (;;) {
linelen = getline(&line, &linesize, stdin);
if (linelen <= 1)
break;
}
free(line);
}
if (client_flags & CLIENT_CONTROLCONTROL) {
printf("\033\\");
fflush(stdout);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
}
} else if (client_exitreason != CLIENT_EXIT_NONE) } else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message()); fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval); return (client_exitval);
} }
/* Send identify messages to server. */ /* Send identify messages to server. */
static void static void
client_send_identify(const char *ttynam, const char *termname, char **caps, client_send_identify(const char *ttynam, const char *cwd)
u_int ncaps, const char *cwd, int feat)
{ {
char **ss; const char *s;
size_t sslen; char **ss;
int fd, flags = client_flags; size_t sslen;
pid_t pid; int fd, flags = client_flags;
u_int i; pid_t pid;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags);
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname, if ((s = getenv("TERM")) == NULL)
strlen(termname) + 1); s = "";
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat); proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1); strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1); proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
for (i = 0; i < ncaps; i++) {
proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
caps[i], strlen(caps[i]) + 1);
}
if ((fd = dup(STDIN_FILENO)) == -1) if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0); proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
pid = getpid(); pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid); proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
@@ -485,6 +447,257 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0); proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
} }
/* File write error callback. */
static void
client_write_error_callback(__unused struct bufferevent *bev,
__unused short what, void *arg)
{
struct client_file *cf = arg;
log_debug("write error file %d", cf->stream);
bufferevent_free(cf->event);
cf->event = NULL;
close(cf->fd);
cf->fd = -1;
if (client_exitflag)
client_exit();
}
/* File write callback. */
static void
client_write_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
if (client_exitflag)
client_exit();
}
/* Open write file. */
static void
client_write_open(void *data, size_t datalen)
{
struct msg_write_open *msg = data;
const char *path;
struct msg_write_ready reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
int error = 0;
if (datalen < sizeof *msg)
fatalx("bad MSG_WRITE_OPEN size");
if (datalen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open write file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
cf = file_create(NULL, msg->stream, NULL, NULL);
RB_INSERT(client_files, &client_files, cf);
} else {
error = EBADF;
goto reply;
}
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, msg->flags|flags, 0644);
else {
if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (~client_flags & CLIENT_CONTROL)
close(msg->fd); /* can only be used once */
}
}
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, NULL, client_write_callback,
client_write_error_callback, cf);
bufferevent_enable(cf->event, EV_WRITE);
goto reply;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(client_peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
}
/* Write to client file. */
static void
client_write_data(void *data, size_t datalen)
{
struct msg_write_data *msg = data;
struct client_file find, *cf;
size_t size = datalen - sizeof *msg;
if (datalen < sizeof *msg)
fatalx("bad MSG_WRITE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("write %zu to file %d", size, cf->stream);
if (cf->event != NULL)
bufferevent_write(cf->event, msg + 1, size);
}
/* Close client file. */
static void
client_write_close(void *data, size_t datalen)
{
struct msg_write_close *msg = data;
struct client_file find, *cf;
if (datalen != sizeof *msg)
fatalx("bad MSG_WRITE_CLOSE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("close file %d", cf->stream);
if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
if (cf->event != NULL)
bufferevent_free(cf->event);
if (cf->fd != -1)
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
}
/* File read callback. */
static void
client_read_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
void *bdata;
size_t bsize;
struct msg_read_data *msg;
size_t msglen;
msg = xmalloc(sizeof *msg);
for (;;) {
bdata = EVBUFFER_DATA(cf->event->input);
bsize = EVBUFFER_LENGTH(cf->event->input);
if (bsize == 0)
break;
if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
log_debug("read %zu from file %d", bsize, cf->stream);
msglen = (sizeof *msg) + bsize;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, bdata, bsize);
proc_send(client_peer, MSG_READ, -1, msg, msglen);
evbuffer_drain(cf->event->input, bsize);
}
free(msg);
}
/* File read error callback. */
static void
client_read_error_callback(__unused struct bufferevent *bev,
__unused short what, void *arg)
{
struct client_file *cf = arg;
struct msg_read_done msg;
log_debug("read error file %d", cf->stream);
msg.stream = cf->stream;
msg.error = 0;
proc_send(client_peer, MSG_READ_DONE, -1, &msg, sizeof msg);
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
/* Open read file. */
static void
client_read_open(void *data, size_t datalen)
{
struct msg_read_open *msg = data;
const char *path;
struct msg_read_done reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_RDONLY;
int error = 0;
if (datalen < sizeof *msg)
fatalx("bad MSG_READ_OPEN size");
if (datalen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open read file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
cf = file_create(NULL, msg->stream, NULL, NULL);
RB_INSERT(client_files, &client_files, cf);
} else {
error = EBADF;
goto reply;
}
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, flags);
else {
if (msg->fd != STDIN_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (~client_flags & CLIENT_CONTROL)
close(msg->fd); /* can only be used once */
}
}
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, client_read_callback, NULL,
client_read_error_callback, cf);
bufferevent_enable(cf->event, EV_READ);
return;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(client_peer, MSG_READ_DONE, -1, &reply, sizeof reply);
}
/* Run command in shell; used for -c. */ /* Run command in shell; used for -c. */
static __dead void static __dead void
client_exec(const char *shell, const char *shellcmd) client_exec(const char *shell, const char *shellcmd)
@@ -523,7 +736,6 @@ client_signal(int sig)
struct sigaction sigact; struct sigaction sigact;
int status; int status;
log_debug("%s: %s", __func__, strsignal(sig));
if (sig == SIGCHLD) if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG); waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) { else if (!client_attached) {
@@ -537,8 +749,7 @@ client_signal(int sig)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case SIGTERM: case SIGTERM:
if (!client_suspended) client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1; client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
@@ -553,31 +764,18 @@ client_signal(int sig)
if (sigaction(SIGTSTP, &sigact, NULL) != 0) if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed"); fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0); proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
client_suspended = 0;
break; break;
} }
} }
} }
/* Callback for file write error or close. */
static void
client_file_check_cb(__unused struct client *c, __unused const char *path,
__unused int error, __unused int closed, __unused struct evbuffer *buffer,
__unused void *data)
{
if (client_exitflag)
client_exit();
}
/* Callback for client read events. */ /* Callback for client read events. */
static void static void
client_dispatch(struct imsg *imsg, __unused void *arg) client_dispatch(struct imsg *imsg, __unused void *arg)
{ {
if (imsg == NULL) { if (imsg == NULL) {
if (!client_exitflag) { client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitval = 1;
client_exitval = 1;
}
proc_exit(client_proc); proc_exit(client_proc);
return; return;
} }
@@ -588,38 +786,13 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
client_dispatch_wait(imsg); client_dispatch_wait(imsg);
} }
/* Process an exit message. */
static void
client_dispatch_exit_message(char *data, size_t datalen)
{
int retval;
if (datalen < sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen >= sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
if (datalen > sizeof retval) {
datalen -= sizeof retval;
data += sizeof retval;
client_exitmessage = xmalloc(datalen);
memcpy(client_exitmessage, data, datalen);
client_exitmessage[datalen - 1] = '\0';
client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
}
}
/* Dispatch imsgs when in wait state (before MSG_READY). */ /* Dispatch imsgs when in wait state (before MSG_READY). */
static void static void
client_dispatch_wait(struct imsg *imsg) client_dispatch_wait(struct imsg *imsg)
{ {
char *data; char *data;
ssize_t datalen; ssize_t datalen;
int retval;
static int pledge_applied; static int pledge_applied;
/* /*
@@ -642,7 +815,12 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) { switch (imsg->hdr.type) {
case MSG_EXIT: case MSG_EXIT:
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
client_dispatch_exit_message(data, datalen); if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
client_exitflag = 1; client_exitflag = 1;
client_exit(); client_exit();
break; break;
@@ -663,14 +841,6 @@ client_dispatch_wait(struct imsg *imsg)
client_exitval = 1; client_exitval = 1;
proc_exit(client_proc); proc_exit(client_proc);
break; break;
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_SHELL: case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string"); fatalx("bad MSG_SHELL string");
@@ -685,20 +855,16 @@ client_dispatch_wait(struct imsg *imsg)
proc_exit(client_proc); proc_exit(client_proc);
break; break;
case MSG_READ_OPEN: case MSG_READ_OPEN:
file_read_open(&client_files, client_peer, imsg, 1, client_read_open(data, datalen);
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break; break;
case MSG_WRITE_OPEN: case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1, client_write_open(data, datalen);
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break; break;
case MSG_WRITE: case MSG_WRITE:
file_write_data(&client_files, imsg); client_write_data(data, datalen);
break; break;
case MSG_WRITE_CLOSE: case MSG_WRITE_CLOSE:
file_write_close(&client_files, imsg); client_write_close(data, datalen);
break; break;
case MSG_OLDSTDERR: case MSG_OLDSTDERR:
case MSG_OLDSTDIN: case MSG_OLDSTDIN:
@@ -721,14 +887,6 @@ client_dispatch_attached(struct imsg *imsg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) { switch (imsg->hdr.type) {
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_DETACH: case MSG_DETACH:
case MSG_DETACHKILL: case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen == 0 || data[datalen - 1] != '\0')
@@ -753,10 +911,11 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXIT: case MSG_EXIT:
client_dispatch_exit_message(data, datalen); if (datalen != 0 && datalen != sizeof (int))
if (client_exitreason == CLIENT_EXIT_NONE) fatalx("bad MSG_EXIT size");
client_exitreason = CLIENT_EXIT_EXITED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
@@ -782,7 +941,6 @@ client_dispatch_attached(struct imsg *imsg)
sigact.sa_handler = SIG_DFL; sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0) if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed"); fatal("sigaction failed");
client_suspended = 1;
kill(getpid(), SIGTSTP); kill(getpid(), SIGTSTP);
break; break;
case MSG_LOCK: case MSG_LOCK:

View File

@@ -37,9 +37,8 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session", .name = "attach-session",
.alias = "attach", .alias = "attach",
.args = { "c:dEf:rt:x", 0, 0 }, .args = { "c:dErt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] [-f flags] " .usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
CMD_TARGET_SESSION_USAGE,
/* -t is special */ /* -t is special */
@@ -49,17 +48,16 @@ const struct cmd_entry cmd_attach_session_entry = {
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int xflag, int rflag, const char *cflag, int Eflag, const char *fflag) int xflag, int rflag, const char *cflag, int Eflag)
{ {
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state target;
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags;
struct client *c = cmdq_get_client(item), *c_loop; struct client *c = item->client, *c_loop;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
char *cwd, *cause; char *cause;
enum msgtype msgtype; enum msgtype msgtype;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
@@ -82,11 +80,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
type = CMD_FIND_SESSION; type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED; flags = CMD_FIND_PREFER_UNATTACHED;
} }
if (cmd_find_target(&target, item, tflag, type, flags) != 0) if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
s = target.s; s = item->target.s;
wl = target.wl; wl = item->target.wl;
wp = target.wp; wp = item->target.wp;
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) if (wp != NULL)
@@ -99,14 +97,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
} }
if (cflag != NULL) { if (cflag != NULL) {
cwd = format_single(item, cflag, c, s, wl, wp);
free((void *)s->cwd); free((void *)s->cwd);
s->cwd = cwd; s->cwd = format_single(item, cflag, c, s, wl, wp);
} }
if (fflag)
server_client_set_flags(c, fflag);
if (rflag)
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
c->last_session = c->session; c->last_session = c->session;
if (c->session != NULL) { if (c->session != NULL) {
@@ -125,7 +118,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
environ_update(s->options, c->environ, s->environ); environ_update(s->options, c->environ, s->environ);
c->session = s; c->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c); tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
@@ -141,6 +134,8 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag || xflag) { if (dflag || xflag) {
if (xflag) if (xflag)
@@ -182,9 +177,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
static enum cmd_retval static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item) cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
return (cmd_attach_session(item, args_get(args, 't'), return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'), args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f'))); args_get(args, 'c'), args_has(args, 'E')));
} }

View File

@@ -33,9 +33,9 @@ const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key", .name = "bind-key",
.alias = "bind", .alias = "bind",
.args = { "nrN:T:", 1, -1 }, .args = { "nrN:T:", 2, -1 },
.usage = "[-nr] [-T key-table] [-N note] key " .usage = "[-nr] [-T key-table] [-N note] key "
"[command [arguments]]", "command [arguments]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec .exec = cmd_bind_key_exec
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_bind_key_entry = {
static enum cmd_retval static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
key_code key; key_code key;
const char *tablename, *note = args_get(args, 'N'); const char *tablename, *note;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
char **argv = args->argv; char **argv = args->argv;
int argc = args->argc, repeat; int argc = args->argc, repeat;
@@ -65,24 +65,22 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
tablename = "prefix"; tablename = "prefix";
repeat = args_has(args, 'r'); repeat = args_has(args, 'r');
if (argc != 1) { if (argc == 2)
if (argc == 2) pr = cmd_parse_from_string(argv[1], NULL);
pr = cmd_parse_from_string(argv[1], NULL); else
else pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL); switch (pr->status) {
switch (pr->status) { case CMD_PARSE_EMPTY:
case CMD_PARSE_EMPTY: cmdq_error(item, "empty command");
cmdq_error(item, "empty command"); return (CMD_RETURN_ERROR);
return (CMD_RETURN_ERROR); case CMD_PARSE_ERROR:
case CMD_PARSE_ERROR: cmdq_error(item, "%s", pr->error);
cmdq_error(item, "%s", pr->error); free(pr->error);
free(pr->error); return (CMD_RETURN_ERROR);
return (CMD_RETURN_ERROR); case CMD_PARSE_SUCCESS:
case CMD_PARSE_SUCCESS: break;
break; }
} note = args_get(args, 'N');
key_bindings_add(tablename, key, note, repeat, pr->cmdlist); key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
} else
key_bindings_add(tablename, key, note, repeat, NULL);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane", .name = "break-pane",
.alias = "breakp", .alias = "breakp",
.args = { "abdPF:n:s:t:", 0, 0 }, .args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-abdP] [-F format] [-n window-name] [-s src-pane] " .usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]", "[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 }, .source = { 's', CMD_FIND_PANE, 0 },
@@ -48,52 +48,31 @@ const struct cmd_entry cmd_break_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *source = cmdq_get_source(item); struct winlink *wl = item->source.wl;
struct client *tc = cmdq_get_target_client(item); struct session *src_s = item->source.s;
struct winlink *wl = source->wl; struct session *dst_s = item->target.s;
struct session *src_s = source->s; struct window_pane *wp = item->source.wp;
struct session *dst_s = target->s;
struct window_pane *wp = source->wp;
struct window *w = wl->window; struct window *w = wl->window;
char *name, *cause, *cp; char *name, *cause;
int idx = target->idx, before; int idx = item->target.idx;
const char *template; const char *template;
char *cp;
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
if (target->wl != NULL)
idx = winlink_shuffle_up(dst_s, target->wl, before);
else
idx = winlink_shuffle_up(dst_s, dst_s->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
if (window_count_panes(w) == 1) {
if (server_link_window(src_s, wl, dst_s, idx, 0,
!args_has(args, 'd'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'n')) {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
server_unlink_window(src_s, wl);
return (CMD_RETURN_NORMAL);
}
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) { if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(item, "index in use: %d", idx); cmdq_error(item, "index %d already in use", idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (window_count_panes(w) == 1) {
cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
server_client_remove_pane(wp);
window_lost_pane(w, wp); window_lost_pane(w, wp);
layout_close_pane(wp); layout_close_pane(wp);
@@ -102,7 +81,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
wp->flags |= PANE_STYLECHANGED; wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;
w->latest = tc; w->latest = c;
if (!args_has(args, 'n')) { if (!args_has(args, 'n')) {
name = default_window_name(w); name = default_window_name(w);
@@ -119,7 +98,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index"); idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */ wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(args, 'd')) { if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx); session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0); cmd_find_from_session(current, dst_s, 0);
} }
@@ -134,7 +113,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE; template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, tc, dst_s, wl, wp); cp = format_single(item, template, c, dst_s, wl, wp);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }

View File

@@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t linelen; size_t linelen;
u_int i; u_int i;
pending = input_pending(wp->ictx); pending = input_pending(wp);
if (pending == NULL) if (pending == NULL)
return (xstrdup("")); return (xstrdup(""));
@@ -118,7 +118,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
sx = screen_size_x(&wp->base); sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
gd = wp->base.saved_grid; gd = wp->saved_grid;
if (gd == NULL) { if (gd == NULL) {
if (!args_has(args, 'q')) { if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen"); cmdq_error(item, "no alternate screen");
@@ -192,14 +192,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
static enum cmd_retval static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct window_pane *wp = cmdq_get_target(item)->wp; struct window_pane *wp = item->target.wp;
char *buf, *cause; char *buf, *cause;
const char *bufname; const char *bufname;
size_t len; size_t len;
if (cmd_get_entry(self) == &cmd_clear_history_entry) { if (self->entry == &cmd_clear_history_entry) {
window_pane_reset_mode_all(wp); window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid); grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -214,20 +214,15 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) { if (args_has(args, 'p')) {
if (len > 0 && buf[len - 1] == '\n') if (!file_can_print(c)) {
len--; cmdq_error(item, "can't write output to client");
if (c->flags & CLIENT_CONTROL)
control_write(c, "%.*s", (int)len, buf);
else {
if (!file_can_print(c)) {
cmdq_error(item, "can't write to client");
free(buf);
return (CMD_RETURN_ERROR);
}
file_print_buffer(c, buf, len);
file_print(c, "\n");
free(buf); free(buf);
return (CMD_RETURN_ERROR);
} }
file_print_buffer(c, buf, len);
if (args_has(args, 'P') && len > 0)
file_print(c, "\n");
free(buf);
} else { } else {
bufname = NULL; bufname = NULL;
if (args_has(args, 'b')) if (args_has(args, 'b'))

View File

@@ -30,9 +30,9 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree", .name = "choose-tree",
.alias = NULL, .alias = NULL,
.args = { "F:f:GK:NO:rst:wZ", 0, 1 }, .args = { "F:Gf:NO:rst:wZ", 0, 1 },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] " .usage = "[-GNrswZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client", .name = "choose-client",
.alias = NULL, .alias = NULL,
.args = { "F:f:K:NO:rt:Z", 0, 1 }, .args = { "F:f:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -58,22 +58,9 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer", .name = "choose-buffer",
.alias = NULL, .alias = NULL,
.args = { "F:f:K:NO:rt:Z", 0, 1 }, .args = { "F:f:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:Z", 0, 0 },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -84,24 +71,21 @@ const struct cmd_entry cmd_customize_mode_entry = {
static enum cmd_retval static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
const struct window_mode *mode; const struct window_mode *mode;
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) { if (self->entry == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL) if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode; mode = &window_buffer_mode;
} else if (cmd_get_entry(self) == &cmd_choose_client_entry) { } else if (self->entry == &cmd_choose_client_entry) {
if (server_client_how_many() == 0) if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
mode = &window_client_mode; mode = &window_client_mode;
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry) } else
mode = &window_customize_mode;
else
mode = &window_tree_mode; mode = &window_tree_mode;
window_pane_set_mode(wp, NULL, mode, target, args); window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -40,11 +40,11 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", .name = "command-prompt",
.alias = NULL, .alias = NULL,
.args = { "1kiI:Np:Tt:W", 0, 1 }, .args = { "1kiI:Np:t:", 0, 1 },
.usage = "[-1kiNTW] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]", "[template]",
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_command_prompt_exec .exec = cmd_command_prompt_exec
}; };
@@ -64,15 +64,17 @@ struct cmd_command_prompt_cdata {
static enum cmd_retval static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item);
const char *inputs, *prompts; const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c;
char *prompt, *ptr, *input = NULL; char *prompt, *ptr, *input = NULL;
size_t n; size_t n;
if (tc->prompt_string != NULL) if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
@@ -122,13 +124,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_INCREMENTAL; cdata->flags |= PROMPT_INCREMENTAL;
else if (args_has(args, 'k')) else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY; cdata->flags |= PROMPT_KEY;
else if (args_has(args, 'W')) status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cdata->flags |= PROMPT_WINDOW; cmd_command_prompt_free, cdata, cdata->flags);
else if (args_has(args, 'T'))
cdata->flags |= PROMPT_TARGET;
status_prompt_set(tc, target, prompt, input,
cmd_command_prompt_callback, cmd_command_prompt_free, cdata,
cdata->flags);
free(prompt); free(prompt);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -139,9 +136,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done) int done)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
char *new_template, *prompt, *ptr, *error; struct cmdq_item *new_item;
char *new_template, *prompt, *ptr;
char *input = NULL; char *input = NULL;
enum cmd_parse_status status; struct cmd_parse_result *pr;
if (s == NULL) if (s == NULL)
return (0); return (0);
@@ -168,10 +166,21 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
return (1); return (1);
} }
status = cmd_parse_and_append(new_template, NULL, c, NULL, &error); pr = cmd_parse_from_string(new_template, NULL);
if (status == CMD_PARSE_ERROR) { switch (pr->status) {
cmdq_append(c, cmdq_get_error(error)); case CMD_PARSE_EMPTY:
free(error); new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
if (!done) if (!done)

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 }, .args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", .usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_confirm_before_exec .exec = cmd_confirm_before_exec
}; };
@@ -53,13 +53,15 @@ struct cmd_confirm_before_data {
static enum cmd_retval static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct cmd_find_state *target = cmdq_get_target(item);
char *cmd, *copy, *new_prompt, *ptr; char *cmd, *copy, *new_prompt, *ptr;
const char *prompt; const char *prompt;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
@@ -72,7 +74,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]); cdata->cmd = xstrdup(args->argv[0]);
status_prompt_set(tc, target, new_prompt, NULL, status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata, cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE); PROMPT_SINGLE);
@@ -85,8 +87,8 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done) __unused int done)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
char *error; struct cmdq_item *new_item;
enum cmd_parse_status status; struct cmd_parse_result *pr;
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
return (0); return (0);
@@ -96,10 +98,21 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0') if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0); return (0);
status = cmd_parse_and_append(cdata->cmd, NULL, c, NULL, &error); pr = cmd_parse_from_string(cdata->cmd, NULL);
if (status == CMD_PARSE_ERROR) { switch (pr->status) {
cmdq_append(c, cmdq_get_error(error)); case CMD_PARSE_EMPTY:
free(error); new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
return (0); return (0);

View File

@@ -30,10 +30,9 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode", .name = "copy-mode",
.alias = NULL, .alias = NULL,
.args = { "eHMs:t:uq", 0, 0 }, .args = { "eHMt:uq", 0, 0 },
.usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE, .usage = "[-eHMuq] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -56,13 +55,11 @@ const struct cmd_entry cmd_clock_mode_entry = {
static enum cmd_retval static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct key_event *event = cmdq_get_event(item); struct cmdq_shared *shared = item->shared;
struct cmd_find_state *source = cmdq_get_source(item); struct client *c = item->client;
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct session *s; struct session *s;
struct window_pane *wp = target->wp, *swp; struct window_pane *wp = item->target.wp;
if (args_has(args, 'q')) { if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp); window_pane_reset_mode_all(wp);
@@ -70,26 +67,22 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&event->m, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_get_entry(self) == &cmd_clock_mode_entry) { if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL); window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 's')) if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
swp = source->wp;
else
swp = wp;
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
if (args_has(args, 'M')) if (args_has(args, 'M'))
window_copy_start_drag(c, &event->m); window_copy_start_drag(c, &shared->mouse);
} }
if (args_has(args, 'u')) if (args_has(self->args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -39,7 +39,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY|CMD_CLIENT_TFLAG, .flags = CMD_READONLY,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
@@ -50,22 +50,24 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item) cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item); struct client *c, *cloop;
struct client *tc = cmdq_get_target_client(item), *loop; struct session *s;
struct session *s; enum msgtype msgtype;
enum msgtype msgtype; const char *cmd = args_get(args, 'E');
const char *cmd = args_get(args, 'E');
if (cmd_get_entry(self) == &cmd_suspend_client_entry) { if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
server_client_suspend(tc); return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) {
server_client_suspend(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -75,35 +77,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = source->s; s = item->source.s;
if (s == NULL) if (s == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(loop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (loop->session == s) { if (cloop->session == s) {
if (cmd != NULL) if (cmd != NULL)
server_client_exec(loop, cmd); server_client_exec(cloop, cmd);
else else
server_client_detach(loop, msgtype); server_client_detach(cloop, msgtype);
} }
} }
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
TAILQ_FOREACH(loop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (loop->session != NULL && loop != tc) { if (cloop->session != NULL && cloop != c) {
if (cmd != NULL) if (cmd != NULL)
server_client_exec(loop, cmd); server_client_exec(cloop, cmd);
else else
server_client_detach(loop, msgtype); server_client_detach(cloop, msgtype);
} }
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd != NULL) if (cmd != NULL)
server_client_exec(tc, cmd); server_client_exec(c, cmd);
else else
server_client_detach(tc, msgtype); server_client_detach(c, msgtype);
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }

View File

@@ -29,255 +29,55 @@
static enum cmd_retval cmd_display_menu_exec(struct cmd *, static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *); struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = { const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu", .name = "display-menu",
.alias = "menu", .alias = "menu",
.args = { "c:t:OT:x:y:", 1, -1 }, .args = { "c:t:T:x:y:", 1, -1 },
.usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] " .usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...", "[-x position] [-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_display_menu_exec .exec = cmd_display_menu_exec
}; };
const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Cc:d:Eh:t:w:x:y:", 0, -1 },
.usage = "[-CE] [-c target-client] [-d start-directory] [-h height] "
CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [command]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_popup_exec
};
static int
cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
{
struct tty *tty = &tc->tty;
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct session *s = tc->session;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct style_ranges *ranges = NULL;
struct style_range *sr = NULL;
const char *xp, *yp;
char *p;
int top;
u_int line, ox, oy, sx, sy, lines, position;
long n;
struct format_tree *ft;
/*
* Work out the position from the -x and -y arguments. This is the
* bottom-left position.
*/
/* If the popup is too big, stop now. */
if (w > tty->sx || h > tty->sy)
return (0);
/* Create format with mouse position if any. */
ft = format_create_from_target(item);
if (event->m.valid) {
format_add(ft, "popup_mouse_x", "%u", event->m.x);
format_add(ft, "popup_mouse_y", "%u", event->m.y);
}
/*
* If there are any status lines, add this window position and the
* status line position.
*/
top = status_at_line(tc);
if (top != -1) {
lines = status_line_size(tc);
if (top == 0)
top = lines;
else
top = 0;
position = options_get_number(s->options, "status-position");
for (line = 0; line < lines; line++) {
ranges = &tc->status.entries[line].ranges;
TAILQ_FOREACH(sr, ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
break;
}
if (line == lines)
ranges = &tc->status.entries[0].ranges;
if (sr != NULL) {
format_add(ft, "popup_window_status_line_x", "%u",
sr->start);
if (position == 0) {
format_add(ft, "popup_window_status_line_y",
"%u", line + 1 + h);
} else {
format_add(ft, "popup_window_status_line_y",
"%u", tty->sy - lines + line);
}
}
if (position == 0)
format_add(ft, "popup_status_line_y", "%u", lines + h);
else {
format_add(ft, "popup_status_line_y", "%u",
tty->sy - lines);
}
} else
top = 0;
/* Popup width and height. */
format_add(ft, "popup_width", "%u", w);
format_add(ft, "popup_height", "%u", h);
/* Position so popup is in the centre. */
n = (long)(tty->sx - 1) / 2 - w / 2;
if (n < 0)
format_add(ft, "popup_centre_x", "%u", 0);
else
format_add(ft, "popup_centre_x", "%ld", n);
n = (tty->sy - 1) / 2 + h / 2;
if (n >= tty->sy)
format_add(ft, "popup_centre_y", "%u", tty->sy - h);
else
format_add(ft, "popup_centre_y", "%ld", n);
/* Position of popup relative to mouse. */
if (event->m.valid) {
n = (long)event->m.x - w / 2;
if (n < 0)
format_add(ft, "popup_mouse_centre_x", "%u", 0);
else
format_add(ft, "popup_mouse_centre_x", "%ld", n);
n = event->m.y - h / 2;
if (n + h >= tty->sy) {
format_add(ft, "popup_mouse_centre_y", "%u",
tty->sy - h);
} else
format_add(ft, "popup_mouse_centre_y", "%ld", n);
n = (long)event->m.y + h;
if (n + h >= tty->sy)
format_add(ft, "popup_mouse_top", "%u", tty->sy - h);
else
format_add(ft, "popup_mouse_top", "%ld", n);
n = event->m.y - h;
if (n < 0)
format_add(ft, "popup_mouse_bottom", "%u", 0);
else
format_add(ft, "popup_mouse_bottom", "%ld", n);
}
/* Position in pane. */
tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
n = top + wp->yoff - oy + h;
if (n >= tty->sy)
format_add(ft, "popup_pane_top", "%u", tty->sy - h);
else
format_add(ft, "popup_pane_top", "%ld", n);
format_add(ft, "popup_pane_bottom", "%u", top + wp->yoff + wp->sy - oy);
format_add(ft, "popup_pane_left", "%u", wp->xoff - ox);
n = (long)wp->xoff + wp->sx - ox - w;
if (n < 0)
format_add(ft, "popup_pane_right", "%u", 0);
else
format_add(ft, "popup_pane_right", "%ld", n);
/* Expand horizontal position. */
xp = args_get(args, 'x');
if (xp == NULL || strcmp(xp, "C") == 0)
xp = "#{popup_centre_x}";
else if (strcmp(xp, "R") == 0)
xp = "#{popup_right}";
else if (strcmp(xp, "P") == 0)
xp = "#{popup_pane_left}";
else if (strcmp(xp, "M") == 0)
xp = "#{popup_mouse_centre_x}";
else if (strcmp(xp, "W") == 0)
xp = "#{popup_window_status_line_x}";
p = format_expand(ft, xp);
n = strtol(p, NULL, 10);
if (n + w >= tty->sx)
n = tty->sx - w;
else if (n < 0)
n = 0;
*px = n;
log_debug("%s: -x: %s = %s = %u", __func__, xp, p, *px);
free(p);
/* Expand vertical position */
yp = args_get(args, 'y');
if (yp == NULL || strcmp(yp, "C") == 0)
yp = "#{popup_centre_y}";
else if (strcmp(yp, "P") == 0)
yp = "#{popup_pane_bottom}";
else if (strcmp(yp, "M") == 0)
yp = "#{popup_mouse_top}";
else if (strcmp(yp, "S") == 0)
yp = "#{popup_status_line_y}";
else if (strcmp(yp, "W") == 0)
yp = "#{popup_window_status_line_y}";
p = format_expand(ft, yp);
n = strtol(p, NULL, 10);
if (n < h)
n = 0;
else
n -= h;
if (n + h >= tty->sy)
n = tty->sy - h;
else if (n < 0)
n = 0;
*py = n;
log_debug("%s: -y: %s = %s = %u", __func__, yp, p, *py);
free(p);
return (1);
}
static enum cmd_retval static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item) cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c;
struct key_event *event = cmdq_get_event(item); struct session *s = item->target.s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct cmd_find_state *fs = &item->target;
struct menu *menu = NULL; struct menu *menu = NULL;
struct style_range *sr;
struct menu_item menu_item; struct menu_item menu_item;
const char *key; const char *xp, *yp, *key;
char *title, *name; char *title, *name;
int flags = 0, i; int at, flags, i;
u_int px, py; u_int px, py, ox, oy, sx, sy;
if (tc->overlay_draw != NULL) if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
at = status_at_line(c);
if (args_has(args, 'T')) if (args_has(args, 'T'))
title = format_single_from_target(item, args_get(args, 'T')); title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
else else
title = xstrdup(""); title = xstrdup("");
menu = menu_create(title); menu = menu_create(title);
for (i = 0; i != args->argc; /* nothing */) { for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++]; name = args->argv[i++];
if (*name == '\0') { if (*name == '\0') {
menu_add_item(menu, NULL, item, tc, target); menu_add_item(menu, NULL, item, c, fs);
continue; continue;
} }
@@ -293,7 +93,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_item.key = key_string_lookup_string(key); menu_item.key = key_string_lookup_string(key);
menu_item.command = args->argv[i++]; menu_item.command = args->argv[i++];
menu_add_item(menu, &menu_item, item, tc, target); menu_add_item(menu, &menu_item, item, c, fs);
} }
free(title); free(title);
if (menu == NULL) { if (menu == NULL) {
@@ -304,94 +104,75 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_free(menu); menu_free(menu);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!cmd_display_menu_get_position(tc, item, args, &px, &py,
menu->width + 4, menu->count + 2)) { xp = args_get(args, 'x');
menu_free(menu); if (xp == NULL)
return (CMD_RETURN_NORMAL); px = 0;
else if (strcmp(xp, "R") == 0)
px = c->tty.sx - 1;
else if (strcmp(xp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->xoff >= ox)
px = wp->xoff - ox;
else
px = 0;
} else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
if (item->shared->mouse.x > (menu->width + 4) / 2)
px = item->shared->mouse.x - (menu->width + 4) / 2;
else
px = 0;
} }
else if (strcmp(xp, "W") == 0) {
if (args_has(args, 'O')) if (at == -1)
flags |= MENU_STAYOPEN; px = 0;
if (!event->m.valid) else {
flags |= MENU_NOMOUSE; TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
if (menu_display(menu, flags, item, px, py, tc, target, NULL, if (sr->type != STYLE_RANGE_WINDOW)
NULL) != 0) continue;
return (CMD_RETURN_NORMAL); if (sr->argument == (u_int)wl->idx)
return (CMD_RETURN_WAIT); break;
} }
if (sr != NULL)
static enum cmd_retval px = sr->start;
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) else
{ px = 0;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct client *tc = cmdq_get_target_client(item);
struct tty *tty = &tc->tty;
const char *value, *shell[] = { NULL, NULL };
const char *shellcmd = NULL;
char *cwd, *cause, **argv = args->argv;
int flags = 0, argc = args->argc;
u_int px, py, w, h;
if (args_has(args, 'C')) {
server_client_clear_overlay(tc);
return (CMD_RETURN_NORMAL);
}
if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
h = tty->sy / 2;
if (args_has(args, 'h')) {
h = args_percentage(args, 'h', 1, tty->sy, tty->sy, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
} }
} } else
px = strtoul(xp, NULL, 10);
if (px + menu->width + 4 >= c->tty.sx)
px = c->tty.sx - menu->width - 4;
w = tty->sx / 2; yp = args_get(args, 'y');
if (args_has(args, 'w')) { if (yp == NULL)
w = args_percentage(args, 'w', 1, tty->sx, tty->sx, &cause); py = 0;
if (cause != NULL) { else if (strcmp(yp, "P") == 0) {
cmdq_error(item, "width %s", cause); tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
free(cause); if (wp->yoff + wp->sy >= oy)
return (CMD_RETURN_ERROR); py = wp->yoff + wp->sy - oy;
} else
} py = 0;
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
if (w > tty->sx - 1) py = item->shared->mouse.y + menu->count + 2;
w = tty->sx - 1; else if (strcmp(yp, "S") == 0) {
if (h > tty->sy - 1) if (at == -1)
h = tty->sy - 1; py = c->tty.sy;
if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h)) else if (at == 0)
return (CMD_RETURN_NORMAL); py = status_line_size(c) + menu->count + 2;
else
value = args_get(args, 'd'); py = at;
if (value != NULL) } else
cwd = format_single_from_target(item, value); py = strtoul(yp, NULL, 10);
if (py < menu->count + 2)
py = 0;
else else
cwd = xstrdup(server_client_get_cwd(tc, s)); py -= menu->count + 2;
if (argc == 0) if (py + menu->count + 2 >= c->tty.sy)
shellcmd = options_get_string(s->options, "default-command"); py = c->tty.sy - menu->count - 2;
else if (argc == 1)
shellcmd = argv[0];
if (argc <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
shellcmd = NULL;
shell[0] = options_get_string(s->options, "default-shell");
if (!checkshell(shell[0]))
shell[0] = _PATH_BSHELL;
argc = 1;
argv = (char**)shell;
}
if (args_has(args, 'E') > 1) flags = 0;
flags |= POPUP_CLOSEEXITZERO; if (!item->shared->mouse.valid)
else if (args_has(args, 'E')) flags |= MENU_NOMOUSE;
flags |= POPUP_CLOSEEXIT; if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
if (popup_display(flags, item, px, py, w, h, shellcmd, argc, argv, cwd,
tc, s, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }

View File

@@ -39,13 +39,13 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", .name = "display-message",
.alias = "display", .alias = "display",
.args = { "acd:INpt:F:v", 0, 1 }, .args = { "ac:Ipt:F:v", 0, 1 },
.usage = "[-aINpv] [-c target-client] [-d delay] [-F format] " .usage = "[-aIpv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
}; };
@@ -60,21 +60,17 @@ cmd_display_message_each(const char *key, const char *value, void *arg)
static enum cmd_retval static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c, *target_c;
struct client *tc = cmdq_get_target_client(item), *c; struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
const char *template; const char *template;
char *msg, *cause; char *msg, *cause;
int delay = -1;
struct format_tree *ft; struct format_tree *ft;
int flags; int flags;
if (args_has(args, 'I')) { if (args_has(args, 'I')) {
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_start_input(wp, item, &cause) != 0) { if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
@@ -88,15 +84,6 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "delay %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
template = args_get(args, 'F'); template = args_get(args, 'F');
if (args->argc != 0) if (args->argc != 0)
template = args->argv[0]; template = args->argv[0];
@@ -109,18 +96,17 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
* formats too, assuming it matches the session. If it doesn't, use the * formats too, assuming it matches the session. If it doesn't, use the
* best client for the session. * best client for the session.
*/ */
if (tc != NULL && tc->session == s) c = cmd_find_client(item, args_get(args, 'c'), 1);
c = tc; if (c != NULL && c->session == s)
else if (s != NULL) target_c = c;
c = cmd_find_best_client(s);
else else
c = NULL; target_c = cmd_find_best_client(s);
if (args_has(args, 'v')) if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE; flags = FORMAT_VERBOSE;
else else
flags = 0; flags = 0;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags); ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, target_c, s, wl, wp);
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item); format_each(ft, cmd_display_message_each, item);
@@ -128,14 +114,10 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
} }
msg = format_expand_time(ft, template); msg = format_expand_time(ft, template);
if (cmdq_get_client(item) == NULL) if (args_has(self->args, 'p'))
cmdq_error(item, "%s", msg);
else if (args_has(args, 'p'))
cmdq_print(item, "%s", msg); cmdq_print(item, "%s", msg);
else if (tc != NULL) { else if (c != NULL)
status_message_set(tc, delay, 0, args_has(args, 'N'), "%s", status_message_set(c, "%s", msg);
msg);
}
free(msg); free(msg);
format_free(ft); format_free(ft);

View File

@@ -34,10 +34,10 @@ const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes", .name = "display-panes",
.alias = "displayp", .alias = "displayp",
.args = { "bd:Nt:", 0, 1 }, .args = { "bd:t:", 0, 1 },
.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]", .usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec .exec = cmd_display_panes_exec
}; };
@@ -55,11 +55,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct session *s = c->session; struct session *s = c->session;
struct options *oo = s->options; struct options *oo = s->options;
struct window *w = wp->window; struct window *w = wp->window;
struct grid_cell fgc, bgc; struct grid_cell gc;
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy; u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour; int colour, active_colour;
char buf[16], lbuf[16], rbuf[16], *ptr; char buf[16], *ptr;
size_t len, llen, rlen; size_t len;
if (wp->xoff + wp->sx <= ctx->ox || if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx || wp->xoff >= ctx->ox + ctx->sx ||
@@ -109,50 +109,31 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px = sx / 2; px = sx / 2;
py = sy / 2; py = sy / 2;
if (window_pane_index(wp, &pane) != 0) if (window_pane_index(wp, &idx) != 0)
fatalx("index not found"); fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", pane); len = xsnprintf(buf, sizeof buf, "%u", idx);
if (sx < len) if (sx < len)
return; return;
colour = options_get_number(oo, "display-panes-colour"); colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour"); active_colour = options_get_number(oo, "display-panes-active-colour");
memcpy(&fgc, &grid_default_cell, sizeof fgc);
memcpy(&bgc, &grid_default_cell, sizeof bgc);
if (w->active == wp) {
fgc.fg = active_colour;
bgc.bg = active_colour;
} else {
fgc.fg = colour;
bgc.bg = colour;
}
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
if (pane > 9 && pane < 35)
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
else
llen = 0;
if (sx < len * 6 || sy < 5) { if (sx < len * 6 || sy < 5) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL); tty_cursor(tty, xoff + px - len / 2, yoff + py);
if (sx >= len + llen + 1) { goto draw_text;
len += llen + 1;
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
tty_putn(tty, " ", 1, 1);
tty_putn(tty, lbuf, llen, llen);
} else {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
}
goto out;
} }
px -= len * 3; px -= len * 3;
py -= 2; py -= 2;
tty_attributes(tty, &bgc, &grid_default_cell, NULL); memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.bg = active_colour;
else
gc.bg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
for (ptr = buf; *ptr != '\0'; ptr++) { for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9') if (*ptr < '0' || *ptr > '9')
continue; continue;
@@ -168,20 +149,22 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px += 6; px += 6;
} }
if (sy <= 6) len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
goto out; if (sx < len || sy < 6)
tty_attributes(tty, &fgc, &grid_default_cell, NULL); return;
if (rlen != 0 && sx >= rlen) { tty_cursor(tty, xoff + sx - len, yoff);
tty_cursor(tty, xoff + sx - rlen, yoff);
tty_putn(tty, rbuf, rlen, rlen); draw_text:
} memcpy(&gc, &grid_default_cell, sizeof gc);
if (llen != 0) { if (w->active == wp)
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1, gc.fg = active_colour;
yoff + py + 5); else
tty_putn(tty, lbuf, llen, llen); gc.fg = colour;
} gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
out:
tty_cursor(tty, 0, 0); tty_cursor(tty, 0, 0);
} }
@@ -214,25 +197,16 @@ static int
cmd_display_panes_key(struct client *c, struct key_event *event) cmd_display_panes_key(struct client *c, struct key_event *event)
{ {
struct cmd_display_panes_data *cdata = c->overlay_data; struct cmd_display_panes_data *cdata = c->overlay_data;
char *cmd, *expanded, *error; struct cmdq_item *new_item;
char *cmd, *expanded;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
enum cmd_parse_status status; struct cmd_parse_result *pr;
u_int index;
key_code key;
if (event->key >= '0' && event->key <= '9') if (event->key < '0' || event->key > '9')
index = event->key - '0';
else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
key = (event->key & KEYC_MASK_KEY);
if (key >= 'a' && key <= 'z')
index = 10 + (key - 'a');
else
return (-1);
} else
return (-1); return (-1);
wp = window_pane_at_index(w, index); wp = window_pane_at_index(w, event->key - '0');
if (wp == NULL) if (wp == NULL)
return (1); return (1);
window_unzoom(w); window_unzoom(w);
@@ -240,10 +214,21 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
xasprintf(&expanded, "%%%u", wp->id); xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(cdata->command, expanded, 1); cmd = cmd_template_replace(cdata->command, expanded, 1);
status = cmd_parse_and_append(cmd, NULL, c, NULL, &error); pr = cmd_parse_from_string(cmd, NULL);
if (status == CMD_PARSE_ERROR) { switch (pr->status) {
cmdq_append(c, cmdq_get_error(error)); case CMD_PARSE_EMPTY:
free(error); new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
free(cmd); free(cmd);
@@ -254,14 +239,18 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
static enum cmd_retval static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct session *s = tc->session; struct session *s;
u_int delay; u_int delay;
char *cause; char *cause;
struct cmd_display_panes_data *cdata; struct cmd_display_panes_data *cdata;
if (tc->overlay_draw != NULL) if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
@@ -284,15 +273,8 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
else else
cdata->item = item; cdata->item = item;
if (args_has(args, 'N')) { server_client_set_overlay(c, delay, cmd_display_panes_draw,
server_client_set_overlay(tc, delay, NULL, NULL, cmd_display_panes_key, cmd_display_panes_free, cdata);
cmd_display_panes_draw, NULL, cmd_display_panes_free,
cdata);
} else {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, cmd_display_panes_key,
cmd_display_panes_free, cdata);
}
if (args_has(args, 'b')) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window", .name = "find-window",
.alias = "findw", .alias = "findw",
.args = { "CiNrt:TZ", 1, 1 }, .args = { "CNrt:TZ", 1, 1 },
.usage = "[-CiNrTZ] " CMD_TARGET_PANE_USAGE " match-string", .usage = "[-CNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -44,10 +44,9 @@ const struct cmd_entry cmd_find_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self), *new_args; struct args *args = self->args, *new_args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; const char *s = args->argv[0];
const char *s = args->argv[0], *suffix = "";
char *filter, *argv = { NULL }; char *filter, *argv = { NULL };
int C, N, T; int C, N, T;
@@ -55,48 +54,69 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
N = args_has(args, 'N'); N = args_has(args, 'N');
T = args_has(args, 'T'); T = args_has(args, 'T');
if (args_has(args, 'r') && args_has(args, 'i'))
suffix = "/ri";
else if (args_has(args, 'r'))
suffix = "/r";
else if (args_has(args, 'i'))
suffix = "/i";
if (!C && !N && !T) if (!C && !N && !T)
C = N = T = 1; C = N = T = 1;
if (C && N && T) { if (!args_has(args, 'r')) {
xasprintf(&filter, if (C && N && T) {
"#{||:" xasprintf(&filter,
"#{C%s:%s},#{||:#{m%s:*%s*,#{window_name}}," "#{||:"
"#{m%s:*%s*,#{pane_title}}}}", "#{C:%s},#{||:#{m:*%s*,#{window_name}},"
suffix, s, suffix, s, suffix, s); "#{m:*%s*,#{pane_title}}}}",
} else if (C && N) { s, s, s);
xasprintf(&filter, } else if (C && N) {
"#{||:#{C%s:%s},#{m%s:*%s*,#{window_name}}}", xasprintf(&filter,
suffix, s, suffix, s); "#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
} else if (C && T) { s, s);
xasprintf(&filter, } else if (C && T) {
"#{||:#{C%s:%s},#{m%s:*%s*,#{pane_title}}}", xasprintf(&filter,
suffix, s, suffix, s); "#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
} else if (N && T) { s, s);
xasprintf(&filter, } else if (N && T) {
"#{||:#{m%s:*%s*,#{window_name}}," xasprintf(&filter,
"#{m%s:*%s*,#{pane_title}}}", "#{||:#{m:*%s*,#{window_name}},"
suffix, s, suffix, s); "#{m:*%s*,#{pane_title}}}",
} else if (C) s, s);
xasprintf(&filter, "#{C%s:%s}", suffix, s); } else if (C)
else if (N) xasprintf(&filter, "#{C:%s}", s);
xasprintf(&filter, "#{m%s:*%s*,#{window_name}}", suffix, s); else if (N)
else xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
xasprintf(&filter, "#{m%s:*%s*,#{pane_title}}", suffix, s); else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
} else {
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C/r:%s},#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C/r:%s},#{m/r:%s,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C/r:%s},#{m/r:%s,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C/r:%s}", s);
else if (N)
xasprintf(&filter, "#{m/r:%s,#{window_name}}", s);
else
xasprintf(&filter, "#{m/r:%s,#{pane_title}}", s);
}
new_args = args_parse("", 1, &argv); new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z')) if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL); args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter); args_set(new_args, 'f', filter);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args); window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
args_free(new_args); args_free(new_args);
free(filter); free(filter);

View File

@@ -587,22 +587,22 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{up-of}") == 0) { } else if (strcmp(pane, "{up-of}") == 0) {
fs->wp = window_pane_find_up(fs->current->wp); fs->wp = window_pane_find_up(fs->w->active);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{down-of}") == 0) { } else if (strcmp(pane, "{down-of}") == 0) {
fs->wp = window_pane_find_down(fs->current->wp); fs->wp = window_pane_find_down(fs->w->active);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{left-of}") == 0) { } else if (strcmp(pane, "{left-of}") == 0) {
fs->wp = window_pane_find_left(fs->current->wp); fs->wp = window_pane_find_left(fs->w->active);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{right-of}") == 0) { } else if (strcmp(pane, "{right-of}") == 0) {
fs->wp = window_pane_find_right(fs->current->wp); fs->wp = window_pane_find_right(fs->w->active);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
@@ -614,7 +614,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
n = strtonum(pane + 1, 1, INT_MAX, NULL); n = strtonum(pane + 1, 1, INT_MAX, NULL);
else else
n = 1; n = 1;
wp = fs->current->wp; wp = fs->w->active;
if (pane[0] == '+') if (pane[0] == '+')
fs->wp = window_pane_next_by_number(fs->w, wp, n); fs->wp = window_pane_next_by_number(fs->w, wp, n);
else else
@@ -866,18 +866,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
/* If this is an attached client, all done. */ /* If this is an attached client, all done. */
if (c->session != NULL) { if (c->session != NULL) {
cmd_find_clear_state(fs, flags); cmd_find_from_session(fs, c->session, flags);
fs->wp = server_client_get_pane(c);
if (fs->wp == NULL) {
cmd_find_from_session(fs, c->session, flags);
return (0);
}
fs->s = c->session;
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0); return (0);
} }
cmd_find_clear_state(fs, flags); cmd_find_clear_state(fs, flags);
@@ -971,11 +960,10 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) { if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane; fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__); log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(cmdq_get_current(item))) { } else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = cmdq_get_current(item); fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__); log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, cmdq_get_client(item), } else if (cmd_find_from_client(&current, item->client, flags) == 0) {
flags) == 0) {
fs->current = &current; fs->current = &current;
log_debug("%s: current is from client", __func__); log_debug("%s: current is from client", __func__);
} else { } else {
@@ -992,7 +980,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* Mouse target is a plain = or {mouse}. */ /* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq_get_event(item)->m; m = &item->shared->mouse;
switch (type) { switch (type) {
case CMD_FIND_PANE: case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl); fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@@ -1242,31 +1230,29 @@ no_pane:
static struct client * static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet) cmd_find_current_client(struct cmdq_item *item, int quiet)
{ {
struct client *c = NULL, *found; struct client *c;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
struct cmd_find_state fs; struct cmd_find_state fs;
if (item != NULL) if (item->client != NULL && item->client->session != NULL)
c = cmdq_get_client(item); return (item->client);
if (c != NULL && c->session != NULL)
return (c);
found = NULL; c = NULL;
if (c != NULL && (wp = cmd_find_inside_pane(c)) != NULL) { if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET); cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window; fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0) if (cmd_find_best_session_with_window(&fs) == 0)
found = cmd_find_best_client(fs.s); c = cmd_find_best_client(fs.s);
} else { } else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET); s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL) if (s != NULL)
found = cmd_find_best_client(s); c = cmd_find_best_client(s);
} }
if (found == NULL && item != NULL && !quiet) if (c == NULL && !quiet)
cmdq_error(item, "no current client"); cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, found); log_debug("%s: no target, return %p", __func__, c);
return (found); return (c);
} }
/* Find the target client or report an error and return NULL. */ /* Find the target client or report an error and return NULL. */

View File

@@ -56,23 +56,26 @@ struct cmd_if_shell_data {
struct client *client; struct client *client;
struct cmdq_item *item; struct cmdq_item *item;
struct mouse_event mouse;
}; };
static enum cmd_retval static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct mouse_event *m = &item->shared->mouse;
struct cmdq_state *state = cmdq_get_state(item);
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *error; char *shellcmd, *cmd;
const char *file; struct cmdq_item *new_item;
struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *fs = &item->target;
struct session *s = target->s; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window_pane *wp = fs->wp;
struct cmd_parse_input pi; struct cmd_parse_input pi;
enum cmd_parse_status status; struct cmd_parse_result *pr;
shellcmd = format_single_from_target(item, args->argv[0]); shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) { if (args_has(args, 'F')) {
if (*shellcmd != '0' && *shellcmd != '\0') if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1]; cmd = args->argv[1];
@@ -85,16 +88,26 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
memset(&pi, 0, sizeof pi); memset(&pi, 0, sizeof pi);
cmd_get_source(self, &pi.file, &pi.line); if (self->file != NULL)
pi.file = self->file;
pi.line = self->line;
pi.item = item; pi.item = item;
pi.c = tc; pi.c = c;
cmd_find_copy_state(&pi.fs, target); cmd_find_copy_state(&pi.fs, fs);
status = cmd_parse_and_insert(cmd, &pi, item, state, &error); pr = cmd_parse_from_string(cmd, &pi);
if (status == CMD_PARSE_ERROR) { switch (pr->status) {
cmdq_error(item, "%s", error); case CMD_PARSE_EMPTY:
free(error); break;
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(pr->cmdlist);
break;
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -106,11 +119,12 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = xstrdup(args->argv[2]); cdata->cmd_else = xstrdup(args->argv[2]);
else else
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
if (!args_has(args, 'b')) if (!args_has(args, 'b'))
cdata->client = cmdq_get_client(item); cdata->client = item->client;
else else
cdata->client = tc; cdata->client = c;
if (cdata->client != NULL) if (cdata->client != NULL)
cdata->client->references++; cdata->client->references++;
@@ -120,18 +134,17 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL; cdata->item = NULL;
memset(&cdata->input, 0, sizeof cdata->input); memset(&cdata->input, 0, sizeof cdata->input);
cmd_get_source(self, &file, &cdata->input.line); if (self->file != NULL)
if (file != NULL) cdata->input.file = xstrdup(self->file);
cdata->input.file = xstrdup(file); cdata->input.line = self->line;
cdata->input.c = tc; cdata->input.item = cdata->item;
cdata->input.c = c;
if (cdata->input.c != NULL) if (cdata->input.c != NULL)
cdata->input.c->references++; cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, target); cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, 0, NULL, s, if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
server_client_get_cwd(cmdq_get_client(item), s), NULL, cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
-1) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd); cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd); free(shellcmd);
free(cdata); free(cdata);
@@ -149,8 +162,8 @@ cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job_get_data(job); struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client; struct client *c = cdata->client;
struct mouse_event *m = &cdata->mouse;
struct cmdq_item *new_item = NULL; struct cmdq_item *new_item = NULL;
struct cmdq_state *new_state = NULL;
char *cmd; char *cmd;
int status; int status;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
@@ -173,13 +186,7 @@ cmd_if_shell_callback(struct job *job)
free(pr->error); free(pr->error);
break; break;
case CMD_PARSE_SUCCESS: case CMD_PARSE_SUCCESS:
if (cdata->item == NULL) new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
new_state = cmdq_new_state(NULL, NULL, 0);
else
new_state = cmdq_get_state(cdata->item);
new_item = cmdq_get_command(pr->cmdlist, new_state);
if (cdata->item == NULL)
cmdq_free_state(new_state);
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
break; break;
} }

View File

@@ -49,8 +49,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane", .name = "move-pane",
.alias = "movep", .alias = "movep",
.args = { "bdfhvp:l:s:t:", 0, 0 }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -62,33 +62,42 @@ const struct cmd_entry cmd_move_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct session *dst_s; struct session *dst_s;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp; struct window_pane *src_wp, *dst_wp;
char *cause = NULL; char *cause, *copy;
int size, percentage, dst_idx; const char *errstr, *p;
size_t plen;
int size, percentage, dst_idx, not_same_window;
int flags; int flags;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
dst_s = target->s; if (self->entry == &cmd_join_pane_entry)
dst_wl = target->wl; not_same_window = 1;
dst_wp = target->wp; else
not_same_window = 0;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
src_wl = source->wl; src_wl = item->source.wl;
src_wp = source->wp; src_wp = item->source.wp;
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w); server_unzoom_window(src_w);
if (src_wp == dst_wp) { if (not_same_window && src_w == dst_w) {
cmdq_error(item, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different"); cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -98,27 +107,40 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
type = LAYOUT_LEFTRIGHT; type = LAYOUT_LEFTRIGHT;
size = -1; size = -1;
if (args_has(args, 'l')) { if ((p = args_get(args, 'l')) != NULL) {
if (type == LAYOUT_TOPBOTTOM) { plen = strlen(p);
size = args_percentage(args, 'l', 0, INT_MAX, if (p[plen - 1] == '%') {
dst_wp->sy, &cause); copy = xstrdup(p);
} else { copy[plen - 1] = '\0';
size = args_percentage(args, 'l', 0, INT_MAX, percentage = strtonum(copy, 0, INT_MAX, &errstr);
dst_wp->sx, &cause); free(copy);
} if (errstr != NULL) {
} else if (args_has(args, 'p')) { cmdq_error(item, "percentage %s", errstr);
percentage = args_strtonum(args, 'p', 0, 100, &cause); return (CMD_RETURN_ERROR);
if (cause == NULL) { }
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100; size = (dst_wp->sy * percentage) / 100;
else else
size = (dst_wp->sx * percentage) / 100; size = (dst_wp->sx * percentage) / 100;
} else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} }
} } else if (args_has(args, 'p')) {
if (cause != NULL) { percentage = args_strtonum(args, 'p', 0, 100, &cause);
cmdq_error(item, "size %s", cause); if (cause != NULL) {
free(cause); cmdq_error(item, "percentage %s", cause);
return (CMD_RETURN_ERROR); free(cause);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
} }
flags = 0; flags = 0;
@@ -135,18 +157,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(src_wp); layout_close_pane(src_wp);
server_client_remove_pane(src_wp);
window_lost_pane(src_w, src_wp); window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry); TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options); options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED; src_wp->flags |= PANE_STYLECHANGED;
if (flags & SPAWN_BEFORE) TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); layout_assign_pane(lc, src_wp);
else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0);
recalculate_sizes(); recalculate_sizes();
@@ -162,7 +180,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_status_session(dst_s); server_status_session(dst_s);
if (window_count_panes(src_w) == 0) if (window_count_panes(src_w) == 0)
server_kill_window(src_w, 1); server_kill_window(src_w);
else else
notify_window("window-layout-changed", src_w); notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w); notify_window("window-layout-changed", dst_w);

View File

@@ -44,17 +44,14 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct winlink *wl = item->target.wl;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
struct winlink *wl = target->wl;
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
if (args_has(args, 'a')) { if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window); server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp) if (loopwp == wp)
continue; continue;
server_client_remove_pane(loopwp);
layout_close_pane(loopwp); layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp); window_remove_pane(wl->window, loopwp);
} }

View File

@@ -54,7 +54,7 @@ const struct cmd_entry cmd_start_server_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item) cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{ {
if (cmd_get_entry(self) == &cmd_kill_server_entry) if (self->entry == &cmd_kill_server_entry)
kill(getpid(), SIGTERM); kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -45,10 +45,11 @@ const struct cmd_entry cmd_kill_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s, *sloop, *stmp;
struct session *s = target->s, *sloop, *stmp; struct winlink *wl;
struct winlink *wl;
s = item->target.s;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {

View File

@@ -55,56 +55,27 @@ const struct cmd_entry cmd_unlink_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl, *wl2, *wl3;
struct winlink *wl = target->wl, *loop;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->target.s;
u_int found;
if (cmd_get_entry(self) == &cmd_unlink_window_entry) { if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(args, 'k') && !session_is_linked(s, w)) { if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session"); cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unlink_window(s, wl); server_unlink_window(s, wl);
recalculate_sizes(); } else {
return (CMD_RETURN_NORMAL); if (args_has(args, 'a')) {
} RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
if (args_has(args, 'a')) { server_kill_window(wl2->window);
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
RB_NEXT(winlinks, &s->windows, wl) == NULL)
return (CMD_RETURN_NORMAL);
/* Kill all windows except the current one. */
do {
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window != wl->window) {
server_kill_window(loop->window, 0);
found++;
break;
}
} }
} while (found != 0); } else
server_kill_window(wl->window);
/*
* If the current window appears in the session more than once,
* kill it as well.
*/
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window == wl->window)
found++;
}
if (found > 1)
server_kill_window(wl->window, 0);
server_renumber_all();
return (CMD_RETURN_NORMAL);
} }
server_kill_window(wl->window, 1); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers", .name = "list-buffers",
.alias = "lsb", .alias = "lsb",
.args = { "F:f:", 0, 0 }, .args = { "F:", 0, 0 },
.usage = "[-F format] [-f filter]", .usage = "[-F format]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec .exec = cmd_list_buffers_exec
@@ -46,33 +46,23 @@ const struct cmd_entry cmd_list_buffers_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item) cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; char *line;
char *line, *expanded; const char *template;
int flag;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE; template = LIST_BUFFERS_TEMPLATE;
filter = args_get(args, 'f');
pb = NULL; pb = NULL;
while ((pb = paste_walk(pb)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb); format_defaults_paste_buffer(ft, pb);
if (filter != NULL) { line = format_expand(ft, template);
expanded = format_expand(ft, filter); cmdq_print(item, "%s", line);
flag = format_true(expanded); free(line);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft); format_free(ft);
} }

View File

@@ -28,10 +28,10 @@
* List all clients. * List all clients.
*/ */
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \ "#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \ "[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}" "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
@@ -51,8 +51,7 @@ const struct cmd_entry cmd_list_clients_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item) cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c; struct client *c;
struct session *s; struct session *s;
struct format_tree *ft; struct format_tree *ft;
@@ -61,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line; char *line;
if (args_has(args, 't')) if (args_has(args, 't'))
s = target->s; s = item->target.s;
else else
s = NULL; s = NULL;
@@ -73,7 +72,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if (c->session == NULL || (s != NULL && s != c->session)) if (c->session == NULL || (s != NULL && s != c->session))
continue; continue;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx); format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);

View File

@@ -68,12 +68,11 @@ cmd_list_keys_get_width(const char *tablename, key_code only)
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL || bd->note == NULL) {
*bd->note == '\0') {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0)); width = utf8_cstrwidth(key_string_lookup_key(bd->key));
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
@@ -86,7 +85,7 @@ static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args, cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix) const char *tablename, u_int keywidth, key_code only, const char *prefix)
{ {
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *key; const char *key;
@@ -100,23 +99,21 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
((bd->note == NULL || *bd->note == '\0') && (bd->note == NULL && !args_has(args, 'a'))) {
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
found = 1; found = 1;
key = key_string_lookup_key(bd->key, 0); key = key_string_lookup_key(bd->key);
if (bd->note == NULL || *bd->note == '\0') if (bd->note == NULL)
note = cmd_list_print(bd->cmdlist, 1); note = cmd_list_print(bd->cmdlist, 1);
else else
note = xstrdup(bd->note); note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1); tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) { if (args_has(args, '1') && c != NULL)
status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp, status_message_set(c, "%s%s%s", prefix, tmp, note);
note); else
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note); cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp); free(tmp);
free(note); free(note);
@@ -136,7 +133,7 @@ cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
*prefix = options_get_number(global_s_options, "prefix"); *prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) { if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE) if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0)); xasprintf(&s, "%s ", key_string_lookup_key(*prefix));
else else
s = xstrdup(""); s = xstrdup("");
} else } else
@@ -147,7 +144,7 @@ cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
static enum cmd_retval static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *tablename, *r; const char *tablename, *r;
@@ -156,7 +153,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
int repeat, width, tablewidth, keywidth, found = 0; int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen; size_t tmpsize, tmpused, cplen;
if (cmd_get_entry(self) == &cmd_list_commands_entry) if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item)); return (cmd_list_keys_commands(self, item));
if (args->argc != 0) { if (args->argc != 0) {
@@ -165,7 +162,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid key: %s", args->argv[0]); cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
only &= KEYC_MASK_KEY;
} }
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
@@ -223,7 +219,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
key = args_escape(key_string_lookup_key(bd->key, 0)); key = args_escape(key_string_lookup_key(bd->key));
if (bd->flags & KEY_BINDING_REPEAT) if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1; repeat = 1;
@@ -257,7 +253,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
continue; continue;
} }
found = 1; found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0)); key = args_escape(key_string_lookup_key(bd->key));
if (!repeat) if (!repeat)
r = ""; r = "";
@@ -273,7 +269,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2; tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize); tmp = xrealloc(tmp, tmpsize);
} }
strlcat(tmp, cp, tmpsize); tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize); tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
@@ -283,7 +279,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2; tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize); tmp = xrealloc(tmp, tmpsize);
} }
strlcat(tmp, cp, tmpsize); tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize); tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
@@ -317,7 +313,7 @@ out:
static enum cmd_retval static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item) cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
const struct cmd_entry **entryp; const struct cmd_entry **entryp;
const struct cmd_entry *entry; const struct cmd_entry *entry;
struct format_tree *ft; struct format_tree *ft;
@@ -333,7 +329,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}"; "#{command_list_usage}";
} }
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) { for (entryp = cmd_table; *entryp != NULL; entryp++) {

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes", .name = "list-panes",
.alias = "lsp", .alias = "lsp",
.args = { "asF:f:t:", 0, 0 }, .args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE, .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -50,10 +50,9 @@ const struct cmd_entry cmd_list_panes_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, item); cmd_list_panes_server(self, item);
@@ -88,13 +87,12 @@ static void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmdq_item *item, int type) struct cmdq_item *item, int type)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
template = args_get(args, 'F'); template = args_get(args, 'F');
if (template == NULL) { if (template == NULL) {
@@ -122,25 +120,16 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
break; break;
} }
} }
filter = args_get(args, 'f');
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp); format_defaults(ft, NULL, s, wl, wp);
if (filter != NULL) { line = format_expand(ft, template);
expanded = format_expand(ft, filter); cmdq_print(item, "%s", line);
flag = format_true(expanded); free(line);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft); format_free(ft);
n++; n++;

View File

@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions", .name = "list-sessions",
.alias = "ls", .alias = "ls",
.args = { "F:f:", 0, 0 }, .args = { "F:", 0, 0 },
.usage = "[-F format] [-f filter]", .usage = "[-F format]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec .exec = cmd_list_sessions_exec
@@ -52,35 +52,25 @@ const struct cmd_entry cmd_list_sessions_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item) cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct session *s; struct session *s;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE; template = LIST_SESSIONS_TEMPLATE;
filter = args_get(args, 'f');
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL); format_defaults(ft, NULL, s, NULL, NULL);
if (filter != NULL) { line = format_expand(ft, template);
expanded = format_expand(ft, filter); cmdq_print(item, "%s", line);
flag = format_true(expanded); free(line);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft); format_free(ft);
n++; n++;

View File

@@ -28,14 +28,14 @@
*/ */
#define LIST_WINDOWS_TEMPLATE \ #define LIST_WINDOWS_TEMPLATE \
"#{window_index}: #{window_name}#{window_raw_flags} " \ "#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \ "(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \ "[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \ "[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}"; "#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \ #define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \ "#{session_name}:" \
"#{window_index}: #{window_name}#{window_raw_flags} " \ "#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \ "(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " "[#{window_width}x#{window_height}] "
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows", .name = "list-windows",
.alias = "lsw", .alias = "lsw",
.args = { "F:f:at:", 0, 0 }, .args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -61,13 +61,12 @@ const struct cmd_entry cmd_list_windows_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item) cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, item); cmd_list_windows_server(self, item);
else else
cmd_list_windows_session(self, target->s, item, 0); cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -85,13 +84,12 @@ static void
cmd_list_windows_session(struct cmd *self, struct session *s, cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmdq_item *item, int type) struct cmdq_item *item, int type)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
template = args_get(args, 'F'); template = args_get(args, 'F');
if (template == NULL) { if (template == NULL) {
@@ -104,25 +102,16 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
break; break;
} }
} }
filter = args_get(args, 'f');
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL); format_defaults(ft, NULL, s, wl, NULL);
if (filter != NULL) { line = format_expand(ft, template);
expanded = format_expand(ft, filter); cmdq_print(item, "%s", line);
flag = format_true(expanded); free(line);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft); format_free(ft);
n++; n++;

View File

@@ -37,15 +37,14 @@ const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer", .name = "load-buffer",
.alias = "loadb", .alias = "loadb",
.args = { "b:t:w", 1, 1 }, .args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " " CMD_TARGET_CLIENT_USAGE " path", .usage = CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_load_buffer_exec .exec = cmd_load_buffer_exec
}; };
struct cmd_load_buffer_data { struct cmd_load_buffer_data {
struct client *client;
struct cmdq_item *item; struct cmdq_item *item;
char *name; char *name;
}; };
@@ -55,7 +54,6 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data) int closed, struct evbuffer *buffer, void *data)
{ {
struct cmd_load_buffer_data *cdata = data; struct cmd_load_buffer_data *cdata = data;
struct client *tc = cdata->client;
struct cmdq_item *item = cdata->item; struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer); void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer); size_t bsize = EVBUFFER_LENGTH(buffer);
@@ -74,12 +72,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
free(copy); free(copy);
} else if (tc != NULL && }
tc->session != NULL &&
(~tc->flags & CLIENT_DEAD))
tty_set_selection(&tc->tty, copy, bsize);
if (tc != NULL)
server_client_unref(tc);
} }
cmdq_continue(item); cmdq_continue(item);
@@ -90,23 +83,24 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
static enum cmd_retval static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item);
struct cmd_load_buffer_data *cdata; struct cmd_load_buffer_data *cdata;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *bufname = args_get(args, 'b'); const char *bufname = args_get(args, 'b');
char *path; char *path;
cdata = xcalloc(1, sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->item = item; cdata->item = item;
if (bufname != NULL) if (bufname != NULL)
cdata->name = xstrdup(bufname); cdata->name = xstrdup(bufname);
if (args_has(args, 'w') && tc != NULL) { else
cdata->client = tc; cdata->name = NULL;
cdata->client->references++;
}
path = format_single_from_target(item, args->argv[0]); path = format_single(item, args->argv[0], c, s, wl, wp);
file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata); file_read(item->client, path, cmd_load_buffer_done, cdata);
free(path); free(path);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);

View File

@@ -57,22 +57,25 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item) cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct cmd_find_state *target = cmdq_get_target(item); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
if (cmd_get_entry(self) == &cmd_lock_server_entry) if (self->entry == &cmd_lock_server_entry)
server_lock(); server_lock();
else if (cmd_get_entry(self) == &cmd_lock_session_entry) else if (self->entry == &cmd_lock_session_entry)
server_lock_session(target->s); server_lock_session(item->target.s);
else else {
server_lock_client(tc); if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_move_window_entry = {
.name = "move-window", .name = "move-window",
.alias = "movew", .alias = "movew",
.args = { "abdkrs:t:", 0, 0 }, .args = { "adkrs:t:", 0, 0 },
.usage = "[-abdkr] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 }, .source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */ /* -t is special */
@@ -46,8 +46,8 @@ const struct cmd_entry cmd_link_window_entry = {
.name = "link-window", .name = "link-window",
.alias = "linkw", .alias = "linkw",
.args = { "abdks:t:", 0, 0 }, .args = { "adks:t:", 0, 0 },
.usage = "[-abdk] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 }, .source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */ /* -t is special */
@@ -59,53 +59,49 @@ const struct cmd_entry cmd_link_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item) cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item); const char *tflag = args_get(args, 't');
struct cmd_find_state target; struct session *src;
const char *tflag = args_get(args, 't'); struct session *dst;
struct session *src = source->s; struct winlink *wl;
struct session *dst; char *cause;
struct winlink *wl = source->wl; int idx, kflag, dflag, sflag;
char *cause;
int idx, kflag, dflag, sflag, before;
if (args_has(args, 'r')) { if (args_has(args, 'r')) {
if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION, if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_QUIET) != 0) CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
session_renumber_windows(target.s); session_renumber_windows(item->target.s);
recalculate_sizes(); recalculate_sizes();
server_status_session(target.s); server_status_session(item->target.s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_find_target(&target, item, tflag, CMD_FIND_WINDOW, if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0) CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
dst = target.s; src = item->source.s;
idx = target.idx; dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
kflag = args_has(args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(args, 'd'); dflag = args_has(self->args, 'd');
sflag = args_has(args, 's'); sflag = args_has(self->args, 's');
before = args_has(args, 'b'); if (args_has(self->args, 'a')) {
if (args_has(args, 'a') || before) { if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
if (target.wl != NULL)
idx = winlink_shuffle_up(dst, target.wl, before);
else
idx = winlink_shuffle_up(dst, dst->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { if (server_link_window(src, wl, dst, idx, kflag, !dflag,
cmdq_error(item, "%s", cause); &cause) != 0) {
cmdq_error(item, "can't link window: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (cmd_get_entry(self) == &cmd_move_window_entry) if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl); server_unlink_window(src, wl);
/* /*

View File

@@ -39,10 +39,10 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session", .name = "new-session",
.alias = "new", .alias = "new",
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1 }, .args = { "Ac:dDEF:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " .usage = "[-AdDEPX] [-c start-directory] [-F format] [-n window-name] "
"[-f flags] [-n window-name] [-s session-name] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", "[-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -66,26 +66,22 @@ const struct cmd_entry cmd_has_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct client *c = item->client;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s, *as, *groupwith;
struct client *c = cmdq_get_client(item);
struct session *s, *as, *groupwith = NULL;
struct environ *env; struct environ *env;
struct options *oo; struct options *oo;
struct termios tio, *tiop; struct termios tio, *tiop;
struct session_group *sg = NULL; struct session_group *sg;
const char *errstr, *template, *group, *tmp, *add; const char *errstr, *template, *group, *prefix, *tmp;
char *cause, *cwd = NULL, *cp, *newname = NULL; char *cause, *cwd = NULL, *cp, *newname = NULL;
char *name, *prefix = NULL;
int detached, already_attached, is_control = 0; int detached, already_attached, is_control = 0;
u_int sx, sy, dsx, dsy; u_int sx, sy, dsx, dsy;
struct spawn_context sc; struct spawn_context sc;
enum cmd_retval retval; enum cmd_retval retval;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *value;
if (cmd_get_entry(self) == &cmd_has_session_entry) { if (self->entry == &cmd_has_session_entry) {
/* /*
* cmd_find_target() will fail if the session cannot be found, * cmd_find_target() will fail if the session cannot be found,
* so always return success here. * so always return success here.
@@ -100,19 +96,21 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
tmp = args_get(args, 's'); tmp = args_get(args, 's');
if (tmp != NULL) { if (tmp != NULL) {
name = format_single(item, tmp, c, NULL, NULL, NULL); newname = format_single(item, tmp, c, NULL, NULL, NULL);
newname = session_check_name(name); if (!session_check_name(newname)) {
free(name); cmdq_error(item, "bad session name: %s", newname);
goto fail;
}
} }
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
if (newname != NULL) if (newname != NULL)
as = session_find(newname); as = session_find(newname);
else else
as = target->s; as = item->target.s;
if (as != NULL) { if (as != NULL) {
retval = cmd_attach_session(item, as->name, retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL, args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E'), args_get(args, 'f')); args_has(args, 'E'));
free(newname); free(newname);
return (retval); return (retval);
} }
@@ -125,17 +123,25 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Is this going to be part of a session group? */ /* Is this going to be part of a session group? */
group = args_get(args, 't'); group = args_get(args, 't');
if (group != NULL) { if (group != NULL) {
groupwith = target->s; groupwith = item->target.s;
if (groupwith == NULL) if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
goto fail;
}
sg = session_group_find(group); sg = session_group_find(group);
else } else
sg = session_group_contains(groupwith); sg = session_group_contains(groupwith);
if (sg != NULL) if (sg != NULL)
prefix = xstrdup(sg->name); prefix = sg->name;
else if (groupwith != NULL) else if (groupwith != NULL)
prefix = xstrdup(groupwith->name); prefix = groupwith->name;
else else
prefix = session_check_name(group); prefix = group;
} else {
groupwith = NULL;
sg = NULL;
prefix = NULL;
} }
/* Set -d if no client. */ /* Set -d if no client. */
@@ -165,16 +171,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* the terminal as that calls tcsetattr() to prepare for tmux taking * the terminal as that calls tcsetattr() to prepare for tmux taking
* over. * over.
*/ */
if (!detached && if (!detached && !already_attached && c->tty.fd != -1) {
!already_attached && if (server_client_check_nested(item->client)) {
c->fd != -1 &&
(~c->flags & CLIENT_CONTROL)) {
if (server_client_check_nested(cmdq_get_client(item))) {
cmdq_error(item, "sessions should be nested with care, " cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force"); "unset $TMUX to force");
goto fail; goto fail;
} }
if (tcgetattr(c->fd, &tio) != 0) if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
tiop = &tio; tiop = &tio;
} else } else
@@ -204,8 +207,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
} }
} else }
dsx = 80;
if (args_has(args, 'y')) { if (args_has(args, 'y')) {
tmp = args_get(args, 'y'); tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) { if (strcmp(tmp, "-") == 0) {
@@ -220,8 +222,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
} }
} else }
dsy = 24;
/* Find new session size. */ /* Find new session size. */
if (!detached && !is_control) { if (!detached && !is_control) {
@@ -232,14 +233,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else { } else {
tmp = options_get_string(global_s_options, "default-size"); tmp = options_get_string(global_s_options, "default-size");
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) { if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = dsx; sx = 80;
sy = dsy; sy = 24;
} else {
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
} }
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
} }
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
@@ -258,17 +258,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
env = environ_create(); env = environ_create();
if (c != NULL && !args_has(args, 'E')) if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env); environ_update(global_s_options, c->environ, env);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(env, add, 0);
add = args_next_value(&value);
}
s = session_create(prefix, newname, cwd, env, oo, tiop); s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Spawn the initial window. */ /* Spawn the initial window. */
memset(&sc, 0, sizeof sc); memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.c = c;
sc.name = args_get(args, 'n'); sc.name = args_get(args, 'n');
sc.argc = args->argc; sc.argc = args->argc;
@@ -309,15 +305,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around. * taking this session and needs to get MSG_READY and stay around.
*/ */
if (!detached) { if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) { if (!already_attached) {
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL) } else if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c); tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
@@ -345,22 +339,20 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp); free(cp);
} }
if (!detached) if (!detached) {
c->flags |= CLIENT_ATTACHED; c->flags |= CLIENT_ATTACHED;
if (!args_has(args, 'd')) cmd_find_from_session(&item->shared->current, s, 0);
cmd_find_from_session(current, s, 0); }
cmd_find_from_session(&fs, s, 0); cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session"); cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd); free(cwd);
free(newname); free(newname);
free(prefix);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail: fail:
free(cwd); free(cwd);
free(newname); free(newname);
free(prefix);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window", .name = "new-window",
.alias = "neww", .alias = "neww",
.args = { "abc:de:F:kn:PSt:", 0, -1 }, .args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]", "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@@ -51,61 +51,28 @@ const struct cmd_entry cmd_new_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc; struct spawn_context sc;
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = item->target.s;
struct winlink *wl = target->wl; struct winlink *wl = item->target.wl;
int idx = target->idx, before; int idx = item->target.idx;
struct winlink *new_wl = NULL; struct winlink *new_wl;
char *cause = NULL, *cp; char *cause = NULL, *cp;
const char *template, *add, *name; const char *template, *add;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *value; struct args_value *value;
/* if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
* If -S and -n are given and -t is not and a single window with this cmdq_error(item, "couldn't get a window index");
* name already exists, select it. return (CMD_RETURN_ERROR);
*/
name = args_get(args, 'n');
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (strcmp(wl->window->name, name) != 0)
continue;
if (new_wl == NULL) {
new_wl = wl;
continue;
}
cmdq_error(item, "multiple windows named %s", name);
return (CMD_RETURN_ERROR);
}
if (new_wl != NULL) {
if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL);
if (session_set_current(s, new_wl) == 0)
server_redraw_session(s);
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
}
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
idx = winlink_shuffle_up(s, wl, before);
if (idx == -1)
idx = target->idx;
} }
memset(&sc, 0, sizeof sc); memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.tc = tc; sc.c = c;
sc.name = args_get(args, 'n'); sc.name = args_get(args, 'n');
sc.argc = args->argc; sc.argc = args->argc;
@@ -114,7 +81,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value); add = args_first_value(args, 'e', &value);
while (add != NULL) { while (add != NULL) {
environ_put(sc.environ, add, 0); environ_put(sc.environ, add);
add = args_next_value(&value); add = args_next_value(&value);
} }
@@ -141,8 +108,8 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE; template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, tc, s, new_wl, cp = format_single(item, template, c, s, new_wl,
new_wl->window->active); new_wl->window->active);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }

View File

@@ -26,7 +26,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <wchar.h>
#include "tmux.h" #include "tmux.h"
@@ -43,6 +42,7 @@ struct cmd_parse_scope {
}; };
struct cmd_parse_command { struct cmd_parse_command {
char *name;
u_int line; u_int line;
int argc; int argc;
@@ -77,7 +77,6 @@ static char *cmd_parse_get_error(const char *, u_int, const char *);
static void cmd_parse_free_command(struct cmd_parse_command *); static void cmd_parse_free_command(struct cmd_parse_command *);
static struct cmd_parse_commands *cmd_parse_new_commands(void); static struct cmd_parse_commands *cmd_parse_new_commands(void);
static void cmd_parse_free_commands(struct cmd_parse_commands *); static void cmd_parse_free_commands(struct cmd_parse_commands *);
static char *cmd_parse_commands_to_string(struct cmd_parse_commands *);
static void cmd_parse_print_commands(struct cmd_parse_input *, u_int, static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
struct cmd_list *); struct cmd_list *);
@@ -100,7 +99,6 @@ static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
} }
%token ERROR %token ERROR
%token HIDDEN
%token IF %token IF
%token ELSE %token ELSE
%token ELIF %token ELIF
@@ -111,8 +109,7 @@ static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
%type <arguments> arguments %type <arguments> arguments
%type <flag> if_open if_elif %type <flag> if_open if_elif
%type <elif> elif elif1 %type <elif> elif elif1
%type <commands> argument_statements statements statement %type <commands> statements statement commands condition condition1
%type <commands> commands condition condition1
%type <command> command %type <command> command
%% %%
@@ -137,11 +134,6 @@ statements : statement '\n'
} }
statement : /* empty */ statement : /* empty */
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| hidden_assignment
{ {
$$ = xmalloc (sizeof *$$); $$ = xmalloc (sizeof *$$);
TAILQ_INIT($$); TAILQ_INIT($$);
@@ -212,21 +204,10 @@ assignment : EQUALS
if ((~flags & CMD_PARSE_PARSEONLY) && if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag)) (ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $1, 0); environ_put(global_environ, $1);
free($1); free($1);
} }
hidden_assignment : HIDDEN EQUALS
{
struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags;
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $2, ENVIRON_HIDDEN);
free($2);
}
if_open : IF expanded if_open : IF expanded
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
@@ -360,7 +341,7 @@ commands : command
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
$$ = cmd_parse_new_commands(); $$ = cmd_parse_new_commands();
if ($1->argc != 0 && if ($1->name != NULL &&
(ps->scope == NULL || ps->scope->flag)) (ps->scope == NULL || ps->scope->flag))
TAILQ_INSERT_TAIL($$, $1, entry); TAILQ_INSERT_TAIL($$, $1, entry);
else else
@@ -380,7 +361,7 @@ commands : command
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
if ($3->argc != 0 && if ($3->name != NULL &&
(ps->scope == NULL || ps->scope->flag)) { (ps->scope == NULL || ps->scope->flag)) {
$$ = $1; $$ = $1;
TAILQ_INSERT_TAIL($$, $3, entry); TAILQ_INSERT_TAIL($$, $3, entry);
@@ -400,6 +381,7 @@ command : assignment
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$); $$ = xcalloc(1, sizeof *$$);
$$->name = NULL;
$$->line = ps->input->line; $$->line = ps->input->line;
} }
| optional_assignment TOKEN | optional_assignment TOKEN
@@ -407,21 +389,20 @@ command : assignment
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$); $$ = xcalloc(1, sizeof *$$);
$$->name = $2;
$$->line = ps->input->line; $$->line = ps->input->line;
cmd_prepend_argv(&$$->argc, &$$->argv, $2);
} }
| optional_assignment TOKEN arguments | optional_assignment TOKEN arguments
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$); $$ = xcalloc(1, sizeof *$$);
$$->name = $2;
$$->line = ps->input->line; $$->line = ps->input->line;
$$->argc = $3.argc; $$->argc = $3.argc;
$$->argv = $3.argv; $$->argv = $3.argv;
cmd_prepend_argv(&$$->argc, &$$->argv, $2);
} }
condition1 : if_open commands if_close condition1 : if_open commands if_close
@@ -525,22 +506,6 @@ argument : TOKEN
{ {
$$ = $1; $$ = $1;
} }
| '{' argument_statements
{
$$ = cmd_parse_commands_to_string($2);
cmd_parse_free_commands($2);
}
argument_statements : statement '}'
{
$$ = $1;
}
| statements statement '}'
{
$$ = $1;
TAILQ_CONCAT($$, $2, entry);
free($2);
}
%% %%
@@ -575,6 +540,7 @@ cmd_parse_print_commands(struct cmd_parse_input *pi, u_int line,
static void static void
cmd_parse_free_command(struct cmd_parse_command *cmd) cmd_parse_free_command(struct cmd_parse_command *cmd)
{ {
free(cmd->name);
cmd_free_argv(cmd->argc, cmd->argv); cmd_free_argv(cmd->argc, cmd->argv);
free(cmd); free(cmd);
} }
@@ -601,30 +567,6 @@ cmd_parse_free_commands(struct cmd_parse_commands *cmds)
free(cmds); free(cmds);
} }
static char *
cmd_parse_commands_to_string(struct cmd_parse_commands *cmds)
{
struct cmd_parse_command *cmd;
char *string = NULL, *s, *line;
TAILQ_FOREACH(cmd, cmds, entry) {
line = cmd_stringify_argv(cmd->argc, cmd->argv);
if (string == NULL)
s = line;
else {
xasprintf(&s, "%s ; %s", s, line);
free(line);
}
free(string);
string = s;
}
if (string == NULL)
string = xstrdup("");
log_debug("%s: %s", __func__, string);
return (string);
}
static struct cmd_parse_commands * static struct cmd_parse_commands *
cmd_parse_run_parser(char **cause) cmd_parse_run_parser(char **cause)
{ {
@@ -685,7 +627,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
int i; int i;
struct cmd_list *cmdlist = NULL, *result; struct cmd_list *cmdlist = NULL, *result;
struct cmd *add; struct cmd *add;
char *name, *alias, *cause, *s; char *alias, *cause, *s;
/* Check for an empty list. */ /* Check for an empty list. */
if (TAILQ_EMPTY(cmds)) { if (TAILQ_EMPTY(cmds)) {
@@ -701,14 +643,12 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
* command list. * command list.
*/ */
TAILQ_FOREACH_SAFE(cmd, cmds, entry, next) { TAILQ_FOREACH_SAFE(cmd, cmds, entry, next) {
name = cmd->argv[0]; alias = cmd_get_alias(cmd->name);
alias = cmd_get_alias(name);
if (alias == NULL) if (alias == NULL)
continue; continue;
line = cmd->line; line = cmd->line;
log_debug("%s: %u %s = %s", __func__, line, name, alias); log_debug("%s: %u %s = %s", __func__, line, cmd->name, alias);
pi->line = line; pi->line = line;
cmds2 = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause); cmds2 = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
@@ -725,7 +665,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
cmd_parse_free_command(cmd); cmd_parse_free_command(cmd);
continue; continue;
} }
for (i = 1; i < cmd->argc; i++) for (i = 0; i < cmd->argc; i++)
cmd_append_argv(&cmd2->argc, &cmd2->argv, cmd->argv[i]); cmd_append_argv(&cmd2->argc, &cmd2->argv, cmd->argv[i]);
after = cmd; after = cmd;
@@ -743,18 +683,15 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
/* /*
* Parse each command into a command list. Create a new command list * Parse each command into a command list. Create a new command list
* for each line (unless the flag is set) so they get a new group (so * for each line so they get a new group (so the queue knows which ones
* the queue knows which ones to remove if a command fails when * to remove if a command fails when executed).
* executed).
*/ */
result = cmd_list_new(); result = cmd_list_new();
TAILQ_FOREACH(cmd, cmds, entry) { TAILQ_FOREACH(cmd, cmds, entry) {
name = cmd->argv[0]; log_debug("%s: %u %s", __func__, cmd->line, cmd->name);
log_debug("%s: %u %s", __func__, cmd->line, name);
cmd_log_argv(cmd->argc, cmd->argv, __func__); cmd_log_argv(cmd->argc, cmd->argv, __func__);
if (cmdlist == NULL || if (cmdlist == NULL || cmd->line != line) {
((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
if (cmdlist != NULL) { if (cmdlist != NULL) {
cmd_parse_print_commands(pi, line, cmdlist); cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist); cmd_list_move(result, cmdlist);
@@ -764,6 +701,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
} }
line = cmd->line; line = cmd->line;
cmd_prepend_argv(&cmd->argc, &cmd->argv, cmd->name);
add = cmd_parse(cmd->argc, cmd->argv, pi->file, line, &cause); add = cmd_parse(cmd->argc, cmd->argv, pi->file, line, &cause);
if (add == NULL) { if (add == NULL) {
cmd_list_free(result); cmd_list_free(result);
@@ -820,74 +758,9 @@ cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi)
struct cmd_parse_result * struct cmd_parse_result *
cmd_parse_from_string(const char *s, struct cmd_parse_input *pi) cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
{ {
struct cmd_parse_input input;
if (pi == NULL) {
memset(&input, 0, sizeof input);
pi = &input;
}
/*
* When parsing a string, put commands in one group even if there are
* multiple lines. This means { a \n b } is identical to "a ; b" when
* given as an argument to another command.
*/
pi->flags |= CMD_PARSE_ONEGROUP;
return (cmd_parse_from_buffer(s, strlen(s), pi)); return (cmd_parse_from_buffer(s, strlen(s), pi));
} }
enum cmd_parse_status
cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi,
struct cmdq_item *after, struct cmdq_state *state, char **error)
{
struct cmd_parse_result *pr;
struct cmdq_item *item;
pr = cmd_parse_from_string(s, pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (error != NULL)
*error = pr->error;
else
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
item = cmdq_get_command(pr->cmdlist, state);
cmdq_insert_after(after, item);
cmd_list_free(pr->cmdlist);
break;
}
return (pr->status);
}
enum cmd_parse_status
cmd_parse_and_append(const char *s, struct cmd_parse_input *pi,
struct client *c, struct cmdq_state *state, char **error)
{
struct cmd_parse_result *pr;
struct cmdq_item *item;
pr = cmd_parse_from_string(s, pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (error != NULL)
*error = pr->error;
else
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
item = cmdq_get_command(pr->cmdlist, state);
cmdq_append(c, item);
cmd_list_free(pr->cmdlist);
break;
}
return (pr->status);
}
struct cmd_parse_result * struct cmd_parse_result *
cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi) cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
{ {
@@ -963,10 +836,11 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi)
i); i);
cmd = xcalloc(1, sizeof *cmd); cmd = xcalloc(1, sizeof *cmd);
cmd->name = xstrdup(new_argv[0]);
cmd->line = pi->line; cmd->line = pi->line;
cmd->argc = new_argc; cmd->argc = new_argc - 1;
cmd->argv = cmd_copy_argv(new_argc, new_argv); cmd->argv = cmd_copy_argv(new_argc - 1, new_argv + 1);
TAILQ_INSERT_TAIL(cmds, cmd, entry); TAILQ_INSERT_TAIL(cmds, cmd, entry);
} }
@@ -982,10 +856,11 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi)
last); last);
cmd = xcalloc(1, sizeof *cmd); cmd = xcalloc(1, sizeof *cmd);
cmd->name = xstrdup(new_argv[0]);
cmd->line = pi->line; cmd->line = pi->line;
cmd->argc = new_argc; cmd->argc = new_argc - 1;
cmd->argv = cmd_copy_argv(new_argc, new_argv); cmd->argv = cmd_copy_argv(new_argc - 1, new_argv + 1);
TAILQ_INSERT_TAIL(cmds, cmd, entry); TAILQ_INSERT_TAIL(cmds, cmd, entry);
} }
@@ -1163,11 +1038,11 @@ yylex(void)
return ('\n'); return ('\n');
} }
if (ch == ';' || ch == '{' || ch == '}') { if (ch == ';') {
/* /*
* A semicolon or { or } is itself. * A semicolon is itself.
*/ */
return (ch); return (';');
} }
if (ch == '#') { if (ch == '#') {
@@ -1204,10 +1079,6 @@ yylex(void)
if (*cp == '\0') if (*cp == '\0')
return (TOKEN); return (TOKEN);
ps->condition = 1; ps->condition = 1;
if (strcmp(yylval.token, "%hidden") == 0) {
free(yylval.token);
return (HIDDEN);
}
if (strcmp(yylval.token, "%if") == 0) { if (strcmp(yylval.token, "%if") == 0) {
free(yylval.token); free(yylval.token);
return (IF); return (IF);
@@ -1292,9 +1163,10 @@ error:
static int static int
yylex_token_escape(char **buf, size_t *len) yylex_token_escape(char **buf, size_t *len)
{ {
int ch, type, o2, o3, mlen; int ch, type, o2, o3;
u_int size, i, tmp; u_int size, i, tmp;
char s[9], m[MB_LEN_MAX]; char s[9];
struct utf8_data ud;
ch = yylex_getc(); ch = yylex_getc();
@@ -1379,12 +1251,11 @@ unicode:
yyerror("invalid \\%c argument", type); yyerror("invalid \\%c argument", type);
return (0); return (0);
} }
mlen = wctomb(m, tmp); if (utf8_split(tmp, &ud) != UTF8_DONE) {
if (mlen <= 0 || mlen > (int)sizeof m) {
yyerror("invalid \\%c argument", type); yyerror("invalid \\%c argument", type);
return (0); return (0);
} }
yylex_append(buf, len, m, mlen); yylex_append(buf, len, ud.data, ud.size);
return (1); return (1);
} }
@@ -1432,7 +1303,7 @@ yylex_token_variable(char **buf, size_t *len)
name[namelen] = '\0'; name[namelen] = '\0';
envent = environ_find(global_environ, name); envent = environ_find(global_environ, name);
if (envent != NULL && envent->value != NULL) { if (envent != NULL) {
value = envent->value; value = envent->value;
log_debug("%s: %s -> %s", __func__, name, value); log_debug("%s: %s -> %s", __func__, name, value);
yylex_append(buf, len, value, strlen(value)); yylex_append(buf, len, value, strlen(value));
@@ -1482,6 +1353,119 @@ yylex_token_tilde(char **buf, size_t *len)
return (1); return (1);
} }
static int
yylex_token_brace(char **buf, size_t *len)
{
struct cmd_parse_state *ps = &parse_state;
int ch, lines = 0, nesting = 1, escape = 0;
int quote = '\0', token = 0;
/*
* Extract a string up to the matching unquoted '}', including newlines
* and handling nested braces.
*
* To detect the final and intermediate braces which affect the nesting
* depth, we scan the input as if it was a tmux config file, and ignore
* braces which would be considered quoted, escaped, or in a comment.
*
* We update the token state after every character because '#' begins a
* comment only when it begins a token. For simplicity, we treat an
* unquoted directive format as comment.
*
* The result is verbatim copy of the input excluding the final brace.
*/
for (ch = yylex_getc1(); ch != EOF; ch = yylex_getc1()) {
yylex_append1(buf, len, ch);
if (ch == '\n')
lines++;
/*
* If the previous character was a backslash (escape is set),
* escape anything if unquoted or in double quotes, otherwise
* escape only '\n' and '\\'.
*/
if (escape &&
(quote == '\0' ||
quote == '"' ||
ch == '\n' ||
ch == '\\')) {
escape = 0;
if (ch != '\n')
token = 1;
continue;
}
/*
* The character is not escaped. If it is a backslash, set the
* escape flag.
*/
if (ch == '\\') {
escape = 1;
continue;
}
escape = 0;
/* A newline always resets to unquoted. */
if (ch == '\n') {
quote = token = 0;
continue;
}
if (quote) {
/*
* Inside quotes or comment. Check if this is the
* closing quote.
*/
if (ch == quote && quote != '#')
quote = 0;
token = 1; /* token continues regardless */
} else {
/* Not inside quotes or comment. */
switch (ch) {
case '"':
case '\'':
case '#':
/* Beginning of quote or maybe comment. */
if (ch != '#' || !token)
quote = ch;
token = 1;
break;
case ' ':
case '\t':
case ';':
/* Delimiter - token resets. */
token = 0;
break;
case '{':
nesting++;
token = 0; /* new commands set - token resets */
break;
case '}':
nesting--;
token = 1; /* same as after quotes */
if (nesting == 0) {
(*len)--; /* remove closing } */
ps->input->line += lines;
return (1);
}
break;
default:
token = 1;
break;
}
}
}
/*
* Update line count after error as reporting the opening line is more
* useful than EOF.
*/
yyerror("unterminated brace string");
ps->input->line += lines;
return (0);
}
static char * static char *
yylex_token(int ch) yylex_token(int ch)
{ {
@@ -1496,37 +1480,23 @@ yylex_token(int ch)
buf = xmalloc(1); buf = xmalloc(1);
for (;;) { for (;;) {
/* EOF or \n are always the end of the token. */ /*
if (ch == EOF || (state == NONE && ch == '\n')) * EOF or \n are always the end of the token. If inside quotes
* they are an error.
*/
if (ch == EOF || ch == '\n') {
if (state != NONE)
goto error;
break; break;
}
/* Whitespace or ; or } ends a token unless inside quotes. */ /* Whitespace or ; ends a token unless inside quotes. */
if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') && if ((ch == ' ' || ch == '\t' || ch == ';') && state == NONE)
state == NONE)
break; break;
/* /*
* Spaces and comments inside quotes after \n are removed but * \ ~ and $ are expanded except in single quotes.
* the \n is left.
*/ */
if (ch == '\n' && state != NONE) {
yylex_append1(&buf, &len, '\n');
while ((ch = yylex_getc()) == ' ' || ch == '\t')
/* nothing */;
if (ch != '#')
continue;
ch = yylex_getc();
if (strchr(",#{}:", ch) != NULL) {
yylex_ungetc(ch);
ch = '#';
} else {
while ((ch = yylex_getc()) != '\n' && ch != EOF)
/* nothing */;
}
continue;
}
/* \ ~ and $ are expanded except in single quotes. */
if (ch == '\\' && state != SINGLE_QUOTES) { if (ch == '\\' && state != SINGLE_QUOTES) {
if (!yylex_token_escape(&buf, &len)) if (!yylex_token_escape(&buf, &len))
goto error; goto error;
@@ -1542,10 +1512,17 @@ yylex_token(int ch)
goto error; goto error;
goto skip; goto skip;
} }
if (ch == '{' && state == NONE) {
if (!yylex_token_brace(&buf, &len))
goto error;
goto skip;
}
if (ch == '}' && state == NONE) if (ch == '}' && state == NONE)
goto error; /* unmatched (matched ones were handled) */ goto error; /* unmatched (matched ones were handled) */
/* ' and " starts or end quotes (and is consumed). */ /*
* ' and " starts or end quotes (and is consumed).
*/
if (ch == '\'') { if (ch == '\'') {
if (state == NONE) { if (state == NONE) {
state = SINGLE_QUOTES; state = SINGLE_QUOTES;
@@ -1567,7 +1544,9 @@ yylex_token(int ch)
} }
} }
/* Otherwise add the character to the buffer. */ /*
* Otherwise add the character to the buffer.
*/
yylex_append1(&buf, &len, ch); yylex_append1(&buf, &len, ch);
skip: skip:

View File

@@ -46,9 +46,8 @@ const struct cmd_entry cmd_paste_buffer_entry = {
static enum cmd_retval static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize; size_t seplen, bufsize;

View File

@@ -55,17 +55,15 @@ const struct cmd_entry cmd_pipe_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; char *cmd;
struct window_pane_offset *wpo = &wp->pipe_offset; int old_fd, pipe_fd[2], null_fd, in, out;
char *cmd; struct format_tree *ft;
int old_fd, pipe_fd[2], null_fd, in, out; sigset_t set, oldset;
struct format_tree *ft;
sigset_t set, oldset;
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@@ -90,13 +88,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
* *
* bind ^p pipep -o 'cat >>~/output' * bind ^p pipep -o 'cat >>~/output'
*/ */
if (args_has(args, 'o') && old_fd != -1) if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */ /* What do we want to do? Neither -I or -O is -O. */
if (args_has(args, 'I')) { if (args_has(self->args, 'I')) {
in = 1; in = 1;
out = args_has(args, 'O'); out = args_has(self->args, 'O');
} else { } else {
in = 0; in = 0;
out = 1; out = 1;
@@ -109,8 +107,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
/* Expand the command. */ /* Expand the command. */
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, tc, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0]); cmd = format_expand_time(ft, args->argv[0]);
format_free(ft); format_free(ft);
@@ -159,7 +157,10 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
close(pipe_fd[1]); close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0]; wp->pipe_fd = pipe_fd[0];
memcpy(wpo, &wp->offset, sizeof *wpo); if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 0;
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd, wp->pipe_event = bufferevent_new(wp->pipe_fd,

View File

@@ -25,69 +25,8 @@
#include "tmux.h" #include "tmux.h"
/* Command queue flags. */ /* Global command queue. */
#define CMDQ_FIRED 0x1 static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
#define CMDQ_WAITING 0x2
/* Command queue item type. */
enum cmdq_type {
CMDQ_COMMAND,
CMDQ_CALLBACK,
};
/* Command queue item. */
struct cmdq_item {
char *name;
struct cmdq_list *queue;
struct cmdq_item *next;
struct client *client;
struct client *target_client;
enum cmdq_type type;
u_int group;
u_int number;
time_t time;
int flags;
struct cmdq_state *state;
struct cmd_find_state source;
struct cmd_find_state target;
struct cmd_list *cmdlist;
struct cmd *cmd;
cmdq_cb cb;
void *data;
TAILQ_ENTRY(cmdq_item) entry;
};
TAILQ_HEAD(cmdq_item_list, cmdq_item);
/*
* Command queue state. This is the context for commands on the command queue.
* It holds information about how the commands were fired (the key and flags),
* any additional formats for the commands, and the current default target.
* Multiple commands can share the same state and a command may update the
* default target.
*/
struct cmdq_state {
int references;
int flags;
struct format_tree *formats;
struct key_event event;
struct cmd_find_state current;
};
/* Command queue. */
struct cmdq_list {
struct cmdq_item *item;
struct cmdq_item_list list;
};
/* Get command queue name. */ /* Get command queue name. */
static const char * static const char *
@@ -108,179 +47,9 @@ cmdq_name(struct client *c)
static struct cmdq_list * static struct cmdq_list *
cmdq_get(struct client *c) cmdq_get(struct client *c)
{ {
static struct cmdq_list *global_queue; if (c == NULL)
return (&global_queue);
if (c == NULL) { return (&c->queue);
if (global_queue == NULL)
global_queue = cmdq_new();
return (global_queue);
}
return (c->queue);
}
/* Create a queue. */
struct cmdq_list *
cmdq_new(void)
{
struct cmdq_list *queue;
queue = xcalloc (1, sizeof *queue);
TAILQ_INIT (&queue->list);
return (queue);
}
/* Free a queue. */
void
cmdq_free(struct cmdq_list *queue)
{
if (!TAILQ_EMPTY(&queue->list))
fatalx("queue not empty");
free(queue);
}
/* Get item name. */
const char *
cmdq_get_name(struct cmdq_item *item)
{
return (item->name);
}
/* Get item client. */
struct client *
cmdq_get_client(struct cmdq_item *item)
{
return (item->client);
}
/* Get item target client. */
struct client *
cmdq_get_target_client(struct cmdq_item *item)
{
return (item->target_client);
}
/* Get item state. */
struct cmdq_state *
cmdq_get_state(struct cmdq_item *item)
{
return (item->state);
}
/* Get item target. */
struct cmd_find_state *
cmdq_get_target(struct cmdq_item *item)
{
return (&item->target);
}
/* Get item source. */
struct cmd_find_state *
cmdq_get_source(struct cmdq_item *item)
{
return (&item->source);
}
/* Get state event. */
struct key_event *
cmdq_get_event(struct cmdq_item *item)
{
return (&item->state->event);
}
/* Get state current target. */
struct cmd_find_state *
cmdq_get_current(struct cmdq_item *item)
{
return (&item->state->current);
}
/* Get state flags. */
int
cmdq_get_flags(struct cmdq_item *item)
{
return (item->state->flags);
}
/* Create a new state. */
struct cmdq_state *
cmdq_new_state(struct cmd_find_state *current, struct key_event *event,
int flags)
{
struct cmdq_state *state;
state = xcalloc(1, sizeof *state);
state->references = 1;
state->flags = flags;
if (event != NULL)
memcpy(&state->event, event, sizeof state->event);
else
state->event.key = KEYC_NONE;
if (current != NULL && cmd_find_valid_state(current))
cmd_find_copy_state(&state->current, current);
else
cmd_find_clear_state(&state->current, 0);
return (state);
}
/* Add a reference to a state. */
struct cmdq_state *
cmdq_link_state(struct cmdq_state *state)
{
state->references++;
return (state);
}
/* Make a copy of a state. */
struct cmdq_state *
cmdq_copy_state(struct cmdq_state *state)
{
return (cmdq_new_state(&state->current, &state->event, state->flags));
}
/* Free a state. */
void
cmdq_free_state(struct cmdq_state *state)
{
if (--state->references != 0)
return;
if (state->formats != NULL)
format_free(state->formats);
free(state);
}
/* Add a format to command queue. */
void
cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...)
{
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (state->formats == NULL)
state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(state->formats, key, "%s", value);
free(value);
}
/* Merge formats from item. */
void
cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft)
{
const struct cmd_entry *entry;
if (item->cmd != NULL) {
entry = cmd_get_entry(item->cmd);
format_add(ft, "command", "%s", entry->name);
}
if (item->state->formats != NULL)
format_merge(ft, item->state->formats);
} }
/* Append an item. */ /* Append an item. */
@@ -299,12 +68,12 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->client = c; item->client = c;
item->queue = queue; item->queue = queue;
TAILQ_INSERT_TAIL(&queue->list, item, entry); TAILQ_INSERT_TAIL(queue, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name); log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next; item = next;
} while (item != NULL); } while (item != NULL);
return (TAILQ_LAST(&queue->list, cmdq_item_list)); return (TAILQ_LAST(queue, cmdq_list));
} }
/* Insert an item. */ /* Insert an item. */
@@ -325,7 +94,7 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
item->client = c; item->client = c;
item->queue = queue; item->queue = queue;
TAILQ_INSERT_AFTER(&queue->list, after, item, entry); TAILQ_INSERT_AFTER(queue, after, item, entry);
log_debug("%s %s: %s after %s", __func__, cmdq_name(c), log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
item->name, after->name); item->name, after->name);
@@ -338,25 +107,17 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
/* Insert a hook. */ /* Insert a hook. */
void void
cmdq_insert_hook(struct session *s, struct cmdq_item *item, cmdq_insert_hook(struct session *s, struct cmdq_item *item,
struct cmd_find_state *current, const char *fmt, ...) struct cmd_find_state *fs, const char *fmt, ...)
{ {
struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd);
struct args_entry *entryp;
struct args_value *valuep;
struct options *oo; struct options *oo;
va_list ap; va_list ap;
char *name, tmp[32], flag, *arguments; char *name;
int i;
const char *value;
struct cmdq_item *new_item; struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
if (item->state->flags & CMDQ_STATE_NOHOOKS) if (item->flags & CMDQ_NOHOOKS)
return; return;
if (s == NULL) if (s == NULL)
oo = global_s_options; oo = global_s_options;
@@ -374,58 +135,24 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
} }
log_debug("running hook %s (parent %p)", name, item); log_debug("running hook %s (parent %p)", name, item);
/*
* The hooks get a new state because they should not update the current
* target or formats for any subsequent commands.
*/
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
cmdq_add_format(new_state, "hook", "%s", name);
arguments = args_print(args);
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
free(arguments);
for (i = 0; i < args->argc; i++) {
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
cmdq_add_format(new_state, tmp, "%s", args->argv[i]);
}
flag = args_first(args, &entryp);
while (flag != 0) {
value = args_get(args, flag);
if (value == NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "1");
} else {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "%s", value);
}
i = 0;
value = args_first_value(args, flag, &valuep);
while (value != NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
cmdq_add_format(new_state, tmp, "%s", value);
i++;
value = args_next_value(&valuep);
}
flag = args_next(&entryp);
}
a = options_array_first(o); a = options_array_first(o);
while (a != NULL) { while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist; cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) { if (cmdlist == NULL) {
new_item = cmdq_get_command(cmdlist, new_state); a = options_array_next(a);
if (item != NULL) continue;
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
} }
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
a = options_array_next(a); a = options_array_next(a);
} }
cmdq_free_state(new_state);
free(name); free(name);
} }
@@ -440,13 +167,19 @@ cmdq_continue(struct cmdq_item *item)
static void static void
cmdq_remove(struct cmdq_item *item) cmdq_remove(struct cmdq_item *item)
{ {
if (item->shared != NULL && --item->shared->references == 0) {
if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL) if (item->client != NULL)
server_client_unref(item->client); server_client_unref(item->client);
if (item->cmdlist != NULL) if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist); cmd_list_free(item->cmdlist);
cmdq_free_state(item->state);
TAILQ_REMOVE(&item->queue->list, item, entry); TAILQ_REMOVE(item->queue, item, entry);
free(item->name); free(item->name);
free(item); free(item);
@@ -471,46 +204,48 @@ cmdq_remove_group(struct cmdq_item *item)
/* Get a command for the command queue. */ /* Get a command for the command queue. */
struct cmdq_item * struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state) cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{ {
struct cmdq_item *item, *first = NULL, *last = NULL; struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd; struct cmd *cmd;
const struct cmd_entry *entry; struct cmdq_shared *shared = NULL;
int created = 0; u_int group = 0;
if (state == NULL) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
state = cmdq_new_state(NULL, NULL, 0); if (cmd->group != group) {
created = 1; shared = xcalloc(1, sizeof *shared);
} if (current != NULL)
cmd_find_copy_state(&shared->current, current);
cmd = cmd_list_first(cmdlist); else
while (cmd != NULL) { cmd_find_clear_state(&shared->current, 0);
entry = cmd_get_entry(cmd); if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
group = cmd->group;
}
item = xcalloc(1, sizeof *item); item = xcalloc(1, sizeof *item);
xasprintf(&item->name, "[%s/%p]", entry->name, item); xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
item->type = CMDQ_COMMAND; item->type = CMDQ_COMMAND;
item->group = cmd_get_group(cmd); item->group = cmd->group;
item->state = cmdq_link_state(state); item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist; item->cmdlist = cmdlist;
item->cmd = cmd; item->cmd = cmd;
cmdlist->references++;
log_debug("%s: %s group %u", __func__, item->name, item->group); log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
if (first == NULL) if (first == NULL)
first = item; first = item;
if (last != NULL) if (last != NULL)
last->next = item; last->next = item;
last = item; last = item;
cmd = cmd_list_next(cmd);
} }
if (created)
cmdq_free_state(state);
return (first); return (first);
} }
@@ -522,11 +257,11 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const char *value; const char *value;
if (flag->flag == 0) { if (flag->flag == 0) {
cmd_find_from_client(fs, item->target_client, 0); cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
value = args_get(cmd_get_args(item->cmd), flag->flag); value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) { if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0); cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -534,75 +269,31 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
/* Add message with command. */
static void
cmdq_add_message(struct cmdq_item *item)
{
struct client *c = item->client;
struct cmdq_state *state = item->state;
const char *name, *key;
char *tmp;
tmp = cmd_print(item->cmd);
if (c != NULL) {
name = c->name;
if (c->session != NULL && state->event.key != KEYC_NONE) {
key = key_string_lookup_key(state->event.key, 0);
server_add_message("%s key %s: %s", name, key, tmp);
} else
server_add_message("%s command: %s", name, tmp);
} else
server_add_message("command: %s", tmp);
free(tmp);
}
/* Fire command on command queue. */ /* Fire command on command queue. */
static enum cmd_retval static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item) cmdq_fire_command(struct cmdq_item *item)
{ {
const char *name = cmdq_name(item->client); struct client *c = item->client;
struct cmdq_state *state = item->state; const char *name = cmdq_name(c);
struct cmdq_shared *shared = item->shared;
struct cmd *cmd = item->cmd; struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd); const struct cmd_entry *entry = cmd->entry;
const struct cmd_entry *entry = cmd_get_entry(cmd);
struct client *tc, *saved = item->client;
enum cmd_retval retval; enum cmd_retval retval;
struct cmd_find_state *fsp, fs; struct cmd_find_state *fsp, fs;
int flags, quiet = 0; int flags;
char *tmp; char *tmp;
if (cfg_finished)
cmdq_add_message(item);
if (log_get_level() > 1) { if (log_get_level() > 1) {
tmp = cmd_print(cmd); tmp = cmd_print(cmd);
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp); log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
free(tmp); free(tmp);
} }
flags = !!(state->flags & CMDQ_STATE_CONTROL); flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
cmdq_guard(item, "begin", flags); cmdq_guard(item, "begin", flags);
if (item->client == NULL) if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1); item->client = cmd_find_client(item, NULL, 1);
if (entry->flags & CMD_CLIENT_CANFAIL)
quiet = 1;
if (entry->flags & CMD_CLIENT_CFLAG) {
tc = cmd_find_client(item, args_get(args, 'c'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else if (entry->flags & CMD_CLIENT_TFLAG) {
tc = cmd_find_client(item, args_get(args, 't'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else
tc = cmd_find_client(item, NULL, 1);
item->target_client = tc;
retval = cmdq_find_flag(item, &item->source, &entry->source); retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
goto out; goto out;
@@ -617,8 +308,8 @@ cmdq_fire_command(struct cmdq_item *item)
if (entry->flags & CMD_AFTERHOOK) { if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target)) if (cmd_find_valid_state(&item->target))
fsp = &item->target; fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current)) else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->state->current; fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0) else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs; fsp = &fs;
else else
@@ -627,7 +318,7 @@ cmdq_fire_command(struct cmdq_item *item)
} }
out: out:
item->client = saved; item->client = c;
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags); cmdq_guard(item, "error", flags);
else else
@@ -646,7 +337,7 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
item->type = CMDQ_CALLBACK; item->type = CMDQ_CALLBACK;
item->group = 0; item->group = 0;
item->state = cmdq_new_state(NULL, NULL, 0); item->flags = 0;
item->cb = cb; item->cb = cb;
item->data = data; item->data = data;
@@ -680,6 +371,25 @@ cmdq_fire_callback(struct cmdq_item *item)
return (item->cb(item, item->data)); return (item->cb(item, item->data));
} }
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
/* Process next item on command queue. */ /* Process next item on command queue. */
u_int u_int
cmdq_next(struct client *c) cmdq_next(struct client *c)
@@ -691,18 +401,18 @@ cmdq_next(struct client *c)
u_int items = 0; u_int items = 0;
static u_int number; static u_int number;
if (TAILQ_EMPTY(&queue->list)) { if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name); log_debug("%s %s: empty", __func__, name);
return (0); return (0);
} }
if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) { if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name); log_debug("%s %s: waiting", __func__, name);
return (0); return (0);
} }
log_debug("%s %s: enter", __func__, name); log_debug("%s %s: enter", __func__, name);
for (;;) { for (;;) {
item = queue->item = TAILQ_FIRST(&queue->list); item = TAILQ_FIRST(queue);
if (item == NULL) if (item == NULL)
break; break;
log_debug("%s %s: %s (%d), flags %x", __func__, name, log_debug("%s %s: %s (%d), flags %x", __func__, name,
@@ -752,7 +462,6 @@ cmdq_next(struct client *c)
} }
cmdq_remove(item); cmdq_remove(item);
} }
queue->item = NULL;
log_debug("%s %s: exit (empty)", __func__, name); log_debug("%s %s: exit (empty)", __func__, name);
return (items); return (items);
@@ -762,19 +471,6 @@ waiting:
return (items); return (items);
} }
/* Get running item if any. */
struct cmdq_item *
cmdq_running(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL)
return (NULL);
if (queue->item->flags & CMDQ_WAITING)
return (NULL);
return (queue->item);
}
/* Print a guard line. */ /* Print a guard line. */
void void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags) cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
@@ -784,7 +480,7 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
u_int number = item->number; u_int number = item->number;
if (c != NULL && (c->flags & CLIENT_CONTROL)) if (c != NULL && (c->flags & CLIENT_CONTROL))
control_write(c, "%%%s %ld %u %d", guard, t, number, flags); file_print(c, "%%%s %ld %u %d\n", guard, t, number, flags);
} }
/* Show message from command. */ /* Show message from command. */
@@ -811,17 +507,12 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
msg = utf8_sanitize(tmp); msg = utf8_sanitize(tmp);
free(tmp); free(tmp);
} }
if (c->flags & CLIENT_CONTROL) file_print(c, "%s\n", msg);
control_write(c, "%s", msg);
else
file_print(c, "%s\n", msg);
} else { } else {
wp = server_client_get_pane(c); wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) { if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
NULL);
}
window_copy_add(wp, "%s", msg); window_copy_add(wp, "%s", msg);
} }
@@ -835,9 +526,8 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
struct client *c = item->client; struct client *c = item->client;
struct cmd *cmd = item->cmd; struct cmd *cmd = item->cmd;
va_list ap; va_list ap;
char *msg, *tmp; char *msg;
const char *file; char *tmp;
u_int line;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
@@ -845,24 +535,22 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
log_debug("%s: %s", __func__, msg); log_debug("%s: %s", __func__, msg);
if (c == NULL) { if (c == NULL)
cmd_get_source(cmd, &file, &line); cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
cfg_add_cause("%s:%u: %s", file, line, msg); else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
server_add_message("%s message: %s", c->name, msg);
if (~c->flags & CLIENT_UTF8) { if (~c->flags & CLIENT_UTF8) {
tmp = msg; tmp = msg;
msg = utf8_sanitize(tmp); msg = utf8_sanitize(tmp);
free(tmp); free(tmp);
} }
if (c->flags & CLIENT_CONTROL) if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg); file_print(c, "%s\n", msg);
else else
file_error(c, "%s\n", msg); file_error(c, "%s\n", msg);
c->retval = 1; c->retval = 1;
} else { } else {
*msg = toupper((u_char) *msg); *msg = toupper((u_char) *msg);
status_message_set(c, -1, 1, 0, "%s", msg); status_message_set(c, "%s", msg);
} }
free(msg); free(msg);

View File

@@ -34,92 +34,28 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "A:B:cC:Df:F:lLRSt:U", 0, 1 }, .args = { "cC:DF:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " .usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
"[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]", " [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
}; };
static void
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
{
char *copy, *split, *name, *what;
enum control_sub_type subtype;
int subid = -1;
copy = name = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL) {
control_remove_sub(tc, copy);
goto out;
}
*split++ = '\0';
what = split;
if ((split = strchr(what, ':')) == NULL)
goto out;
*split++ = '\0';
if (strcmp(what, "%*") == 0)
subtype = CONTROL_SUB_ALL_PANES;
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_PANE;
else if (strcmp(what, "@*") == 0)
subtype = CONTROL_SUB_ALL_WINDOWS;
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_WINDOW;
else
subtype = CONTROL_SUB_SESSION;
control_add_sub(tc, name, subtype, subid, split);
out:
free(copy);
}
static void
cmd_refresh_client_update_offset(struct client *tc, const char *value)
{
struct window_pane *wp;
char *copy, *split;
u_int pane;
if (*value != '%')
return;
copy = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL)
goto out;
*split++ = '\0';
if (sscanf(copy, "%%%u", &pane) != 1)
goto out;
wp = window_pane_find_by_id(pane);
if (wp == NULL)
goto out;
if (strcmp(split, "on") == 0)
control_set_pane_on(tc, wp);
else if (strcmp(split, "off") == 0)
control_set_pane_off(tc, wp);
else if (strcmp(split, "continue") == 0)
control_continue_pane(tc, wp);
else if (strcmp(split, "pause") == 0)
control_pause_pane(tc, wp);
out:
free(copy);
}
static enum cmd_retval static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct tty *tty = &tc->tty; struct tty *tty;
struct window *w; struct window *w;
const char *size, *errstr, *value; const char *size, *errstr;
u_int x, y, adjust; char *copy, *next, *s;
struct args_value *av; u_int x, y, adjust;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty = &c->tty;
if (args_has(args, 'c') || if (args_has(args, 'c') ||
args_has(args, 'L') || args_has(args, 'L') ||
@@ -138,99 +74,88 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'c')) if (args_has(args, 'c'))
tc->pan_window = NULL; c->pan_window = NULL;
else { else {
w = tc->session->curw->window; w = c->session->curw->window;
if (tc->pan_window != w) { if (c->pan_window != w) {
tc->pan_window = w; c->pan_window = w;
tc->pan_ox = tty->oox; c->pan_ox = tty->oox;
tc->pan_oy = tty->ooy; c->pan_oy = tty->ooy;
} }
if (args_has(args, 'L')) { if (args_has(args, 'L')) {
if (tc->pan_ox > adjust) if (c->pan_ox > adjust)
tc->pan_ox -= adjust; c->pan_ox -= adjust;
else else
tc->pan_ox = 0; c->pan_ox = 0;
} else if (args_has(args, 'R')) { } else if (args_has(args, 'R')) {
tc->pan_ox += adjust; c->pan_ox += adjust;
if (tc->pan_ox > w->sx - tty->osx) if (c->pan_ox > w->sx - tty->osx)
tc->pan_ox = w->sx - tty->osx; c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) { } else if (args_has(args, 'U')) {
if (tc->pan_oy > adjust) if (c->pan_oy > adjust)
tc->pan_oy -= adjust; c->pan_oy -= adjust;
else else
tc->pan_oy = 0; c->pan_oy = 0;
} else if (args_has(args, 'D')) { } else if (args_has(args, 'D')) {
tc->pan_oy += adjust; c->pan_oy += adjust;
if (tc->pan_oy > w->sy - tty->osy) if (c->pan_oy > w->sy - tty->osy)
tc->pan_oy = w->sy - tty->osy; c->pan_oy = w->sy - tty->osy;
} }
} }
tty_update_client_offset(tc); tty_update_client_offset(c);
server_redraw_client(tc); server_redraw_client(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
tty_putcode_ptr2(&tc->tty, TTYC_MS, "", "?"); if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'F')) /* -F is an alias for -f */ if (args_has(args, 'C') || args_has(args, 'F')) {
server_client_set_flags(tc, args_get(args, 'F')); if (args_has(args, 'C')) {
if (args_has(args, 'f')) if (!(c->flags & CLIENT_CONTROL)) {
server_client_set_flags(tc, args_get(args, 'f')); cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
if (args_has(args, 'A')) { }
if (~tc->flags & CLIENT_CONTROL) size = args_get(args, 'C');
goto not_control_client; if (sscanf(size, "%u,%u", &x, &y) != 2 &&
value = args_first_value(args, 'A', &av); sscanf(size, "%ux%u", &x, &y) != 2) {
while (value != NULL) { cmdq_error(item, "bad size argument");
cmd_refresh_client_update_offset(tc, value); return (CMD_RETURN_ERROR);
value = args_next_value(&av); }
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, x, y, 0, 0);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
} }
return (CMD_RETURN_NORMAL); if (args_has(args, 'F')) {
} if (!(c->flags & CLIENT_CONTROL)) {
if (args_has(args, 'B')) { cmdq_error(item, "not a control client");
if (~tc->flags & CLIENT_CONTROL) return (CMD_RETURN_ERROR);
goto not_control_client; }
value = args_first_value(args, 'B', &av); s = copy = xstrdup(args_get(args, 'F'));
while (value != NULL) { while ((next = strsep(&s, ",")) != NULL) {
cmd_refresh_client_update_subscription(tc, value); /* Unknown flags are ignored. */
value = args_next_value(&av); if (strcmp(next, "no-output") == 0)
c->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'C')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
size = args_get(args, 'C');
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&tc->tty, x, y, 0, 0);
tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes_now(1);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) { if (args_has(args, 'S')) {
tc->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_status_client(tc); server_status_client(c);
} else { } else {
tc->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(tc); server_redraw_client(c);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
not_control_client:
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
} }

View File

@@ -46,18 +46,22 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = item->target.s;
char *newname, *tmp; char *newname;
tmp = format_single_from_target(item, args->argv[0]); newname = format_single(item, args->argv[0], c, s, NULL, NULL);
newname = session_check_name(tmp);
free(tmp);
if (strcmp(newname, s->name) == 0) { if (strcmp(newname, s->name) == 0) {
free(newname); free(newname);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname); cmdq_error(item, "duplicate session: %s", newname);
free(newname); free(newname);

View File

@@ -45,16 +45,16 @@ const struct cmd_entry cmd_rename_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = target->wl; struct session *s = item->target.s;
char *newname; struct winlink *wl = item->target.wl;
char *newname;
newname = format_single_from_target(item, args->argv[0]); newname = format_single(item, args->argv[0], c, s, wl, NULL);
window_set_name(wl->window, newname); window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0); options_set_number(wl->window->options, "automatic-rename", 0);
server_redraw_window_borders(wl->window);
server_status_window(wl->window); server_status_window(wl->window);
free(newname); free(newname);

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane", .name = "resize-pane",
.alias = "resizep", .alias = "resizep",
.args = { "DLMRTt:Ux:y:Z", 0, 1 }, .args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]", "[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -49,39 +49,26 @@ const struct cmd_entry cmd_resize_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct cmdq_shared *shared = item->shared;
struct key_event *event = cmdq_get_event(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct session *s = target->s; struct session *s = item->target.s;
const char *errstr; const char *errstr, *p;
char *cause; char *cause, *copy;
u_int adjust; u_int adjust;
int x, y; int x, y, percentage;
struct grid *gd = wp->base.grid; size_t plen;
if (args_has(args, 'T')) {
if (!TAILQ_EMPTY(&wp->modes))
return (CMD_RETURN_NORMAL);
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
if (adjust > gd->hsize)
adjust = gd->hsize;
grid_remove_history(gd, adjust);
wp->base.cy += adjust;
wp->flags |= PANE_REDRAW;
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (!event->m.valid || cmd_mouse_window(&event->m, &s) == NULL) if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &event->m); cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -91,6 +78,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
else else
window_zoom(wp); window_zoom(wp);
server_redraw_window(w); server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
server_unzoom_window(w); server_unzoom_window(w);
@@ -105,21 +93,58 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
if (args_has(args, 'x')) { if ((p = args_get(args, 'x')) != NULL) {
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause); plen = strlen(p);
if (cause != NULL) { if (p[plen - 1] == '%') {
cmdq_error(item, "width %s", cause); copy = xstrdup(p);
free(cause); copy[plen - 1] = '\0';
return (CMD_RETURN_ERROR); percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
return (CMD_RETURN_ERROR);
}
x = (w->sx * percentage) / 100;
if (x < PANE_MINIMUM)
x = PANE_MINIMUM;
if (x > INT_MAX)
x = INT_MAX;
} else {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} }
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
} }
if (args_has(args, 'y')) { if ((p = args_get(args, 'y')) != NULL) {
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause); plen = strlen(p);
if (cause != NULL) { if (p[plen - 1] == '%') {
cmdq_error(item, "height %s", cause); copy = xstrdup(p);
free(cause); copy[plen - 1] = '\0';
return (CMD_RETURN_ERROR); percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
return (CMD_RETURN_ERROR);
}
y = (w->sy * percentage) / 100;
if (y < PANE_MINIMUM)
y = PANE_MINIMUM;
if (y > INT_MAX)
y = INT_MAX;
}
else {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} }
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
} }

View File

@@ -46,11 +46,10 @@ const struct cmd_entry cmd_resize_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->target.s;
const char *errstr; const char *errstr;
char *cause; char *cause;
u_int adjust, sx, sy; u_int adjust, sx, sy;

View File

@@ -47,12 +47,11 @@ const struct cmd_entry cmd_respawn_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc; struct spawn_context sc;
struct session *s = target->s; struct session *s = item->target.s;
struct winlink *wl = target->wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = target->wp; struct window_pane *wp = item->target.wp;
char *cause = NULL; char *cause = NULL;
const char *add; const char *add;
struct args_value *value; struct args_value *value;
@@ -72,7 +71,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value); add = args_first_value(args, 'e', &value);
while (add != NULL) { while (add != NULL) {
environ_put(sc.environ, add, 0); environ_put(sc.environ, add);
add = args_next_value(&value); add = args_next_value(&value);
} }
@@ -90,7 +89,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
environ_free(sc.environ); environ_free(sc.environ);

View File

@@ -47,12 +47,10 @@ const struct cmd_entry cmd_respawn_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc; struct spawn_context sc;
struct client *tc = cmdq_get_target_client(item); struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
char *cause = NULL; char *cause = NULL;
const char *add; const char *add;
struct args_value *value; struct args_value *value;
@@ -61,7 +59,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.wl = wl; sc.wl = wl;
sc.tc = tc; sc.c = cmd_find_client(item, NULL, 1);
sc.name = NULL; sc.name = NULL;
sc.argc = args->argc; sc.argc = args->argc;
@@ -70,7 +68,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value); add = args_first_value(args, 'e', &value);
while (add != NULL) { while (add != NULL) {
environ_put(sc.environ, add, 0); environ_put(sc.environ, add);
add = args_next_value(&value); add = args_next_value(&value);
} }

View File

@@ -43,18 +43,16 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item); struct winlink *wl = item->target.wl;
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
window_push_zoom(w, 0, args_has(args, 'Z')); window_push_zoom(w, args_has(self->args, 'Z'));
if (args_has(args, 'D')) { if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);

View File

@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -32,7 +31,6 @@
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
static void cmd_run_shell_timer(int, short, void *);
static void cmd_run_shell_callback(struct job *); static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *); static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *); static void cmd_run_shell_print(struct job *, const char *);
@@ -41,8 +39,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell", .name = "run-shell",
.alias = "run", .alias = "run",
.args = { "bd:Ct:", 0, 1 }, .args = { "bt:", 1, 1 },
.usage = "[-bC] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]", .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -51,16 +49,9 @@ const struct cmd_entry cmd_run_shell_entry = {
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
struct client *client;
char *cmd; char *cmd;
int shell;
char *cwd;
struct cmdq_item *item; struct cmdq_item *item;
struct session *s;
int wp_id; int wp_id;
struct event timer;
int flags;
struct cmd_parse_input pi;
}; };
static void static void
@@ -87,130 +78,48 @@ cmd_run_shell_print(struct job *job, const char *msg)
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL); window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg); window_copy_add(wp, "%s", msg);
} }
static enum cmd_retval static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = item->target.s;
struct window_pane *wp = target->wp; struct winlink *wl = item->target.wl;
const char *delay; struct window_pane *wp = item->target.wp;
double d;
struct timeval tv;
char *end;
int wait = !args_has(args, 'b');
if ((delay = args_get(args, 'd')) != NULL) {
d = strtod(delay, &end);
if (*end != '\0') {
cmdq_error(item, "invalid delay time: %s", delay);
return (CMD_RETURN_ERROR);
}
} else if (args->argc == 0)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
if (args->argc != 0) cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
cdata->cmd = format_single_from_target(item, args->argv[0]);
cdata->shell = !args_has(args, 'C');
if (!cdata->shell) {
memset(&cdata->pi, 0, sizeof cdata->pi);
cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
if (wait)
cdata->pi.item = item;
cdata->pi.c = tc;
cmd_find_copy_state(&cdata->pi.fs, target);
}
if (args_has(args, 't') && wp != NULL) if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id; cdata->wp_id = wp->id;
else else
cdata->wp_id = -1; cdata->wp_id = -1;
if (wait) { if (!args_has(args, 'b'))
cdata->client = cmdq_get_client(item);
cdata->item = item; cdata->item = item;
} else {
cdata->client = tc; if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cdata->flags |= JOB_NOWAIT; cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", cdata->cmd);
free(cdata);
return (CMD_RETURN_ERROR);
} }
if (cdata->client != NULL)
cdata->client->references++;
cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s)); if (args_has(args, 'b'))
cdata->s = s;
if (s != NULL)
session_add_ref(s, __func__);
evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
if (delay != NULL) {
timerclear(&tv);
tv.tv_sec = (time_t)d;
tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
evtimer_add(&cdata->timer, &tv);
} else
event_active(&cdata->timer, EV_TIMEOUT, 1);
if (!wait)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
static void
cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
{
struct cmd_run_shell_data *cdata = arg;
struct client *c = cdata->client;
const char *cmd = cdata->cmd;
char *error;
struct cmdq_item *item = cdata->item;
enum cmd_parse_status status;
if (cmd != NULL && cdata->shell) {
if (job_run(cmd, 0, NULL, cdata->s, cdata->cwd, NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata,
cdata->flags, -1, -1) == NULL)
cmd_run_shell_free(cdata);
return;
}
if (cmd != NULL) {
if (item != NULL) {
status = cmd_parse_and_insert(cmd, &cdata->pi, item,
cmdq_get_state(item), &error);
} else {
status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL,
&error);
}
if (status == CMD_PARSE_ERROR) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);
}
}
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
}
static void static void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job_get_data(job); struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job); struct bufferevent *event = job_get_event(job);
struct cmdq_item *item = cdata->item;
char *cmd = cdata->cmd, *msg = NULL, *line; char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size; size_t size;
int retcode, status; int retcode, status;
@@ -240,19 +149,13 @@ cmd_run_shell_callback(struct job *job)
} else if (WIFSIGNALED(status)) { } else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status); retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
retcode += 128; }
} else
retcode = 0;
if (msg != NULL) if (msg != NULL)
cmd_run_shell_print(job, msg); cmd_run_shell_print(job, msg);
free(msg); free(msg);
if (item != NULL) { if (cdata->item != NULL)
if (cmdq_get_client(item) != NULL && cmdq_continue(cdata->item);
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
} }
static void static void
@@ -260,12 +163,6 @@ cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
evtimer_del(&cdata->timer);
if (cdata->s != NULL)
session_remove_ref(cdata->s, __func__);
if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cwd);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);
} }

View File

@@ -72,13 +72,16 @@ cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
static enum cmd_retval static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb; struct paste_buffer *pb;
int flags; int flags;
const char *bufname = args_get(args, 'b'), *bufdata; const char *bufname = args_get(args, 'b'), *bufdata;
size_t bufsize; size_t bufsize;
char *path, *tmp; char *path;
if (bufname == NULL) { if (bufname == NULL) {
if ((pb = paste_get_top(NULL)) == NULL) { if ((pb = paste_get_top(NULL)) == NULL) {
@@ -94,22 +97,15 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
} }
bufdata = paste_buffer_data(pb, &bufsize); bufdata = paste_buffer_data(pb, &bufsize);
if (cmd_get_entry(self) == &cmd_show_buffer_entry) { if (self->entry == &cmd_show_buffer_entry)
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
utf8_stravisx(&tmp, bufdata, bufsize,
VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
cmdq_print(item, "%s", tmp);
free(tmp);
return (CMD_RETURN_NORMAL);
}
path = xstrdup("-"); path = xstrdup("-");
} else else
path = format_single_from_target(item, args->argv[0]); path = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'a')) if (args_has(self->args, 'a'))
flags = O_APPEND; flags = O_APPEND;
else else
flags = O_TRUNC; flags = 0;
file_write(cmdq_get_client(item), path, flags, bufdata, bufsize, file_write(item->client, path, flags, bufdata, bufsize,
cmd_save_buffer_done, item); cmd_save_buffer_done, item);
free(path); free(path);

View File

@@ -71,21 +71,20 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item) cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp = target->wp; struct window_pane *wp = item->target.wp;
const char *layoutname; const char *layoutname;
char *oldlayout; char *oldlayout;
int next, previous, layout; int next, previous, layout;
server_unzoom_window(w); server_unzoom_window(w);
next = (cmd_get_entry(self) == &cmd_next_layout_entry); next = self->entry == &cmd_next_layout_entry;
if (args_has(args, 'n')) if (args_has(args, 'n'))
next = 1; next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_layout_entry); previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p')) if (args_has(args, 'p'))
previous = 1; previous = 1;

View File

@@ -83,21 +83,19 @@ cmd_select_pane_redraw(struct window *w)
static enum cmd_retval static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
const struct cmd_entry *entry = cmd_get_entry(self); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item); struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct client *c = cmdq_get_client(item);
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->target.s;
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp; struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct options *oo = wp->options; char *pane_title;
char *title;
const char *style; const char *style;
struct style *sy;
struct options_entry *o; struct options_entry *o;
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last; lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) { if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry); lastwp = TAILQ_PREV(w->active, window_panes, entry);
@@ -108,16 +106,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last pane"); cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'e')) { if (args_has(self->args, 'e'))
lastwp->flags &= ~PANE_INPUTOFF; lastwp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window); else if (args_has(self->args, 'd'))
server_status_window(lastwp->window);
} else if (args_has(args, 'd')) {
lastwp->flags |= PANE_INPUTOFF; lastwp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window); else {
server_status_window(lastwp->window); if (window_push_zoom(w, args_has(self->args, 'Z')))
} else {
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, lastwp); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) { if (window_set_active_pane(w, lastwp, 1)) {
@@ -133,10 +127,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'm') || args_has(args, 'M')) { if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp)) if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (server_check_marked()) lastwp = marked_pane.wp;
lastwp = marked_pane.wp;
else
lastwp = NULL;
if (args_has(args, 'M') || server_is_marked(s, wl, wp)) if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked(); server_clear_marked();
@@ -155,80 +146,73 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
style = args_get(args, 'P'); if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (style != NULL) { if ((style = args_get(args, 'P')) != NULL) {
o = options_set_string(oo, "window-style", 0, "%s", style); o = options_set_style(wp->options, "window-style", 0,
if (o == NULL) { style);
cmdq_error(item, "bad style: %s", style); if (o == NULL) {
return (CMD_RETURN_ERROR); cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
options_set_style(wp->options, "window-active-style", 0,
style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
if (args_has(self->args, 'g')) {
sy = options_get_style(wp->options, "window-style");
cmdq_print(item, "%s", style_tostring(sy));
} }
options_set_string(oo, "window-active-style", 0, "%s", style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'L')) { if (args_has(self->args, 'L')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_left(wp); wp = window_pane_find_left(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'R')) { } else if (args_has(self->args, 'R')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_right(wp); wp = window_pane_find_right(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'U')) { } else if (args_has(self->args, 'U')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_up(wp); wp = window_pane_find_up(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'D')) { } else if (args_has(self->args, 'D')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_down(wp); wp = window_pane_find_down(wp);
window_pop_zoom(w); window_pop_zoom(w);
} }
if (wp == NULL) if (wp == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'e')) { if (args_has(self->args, 'e')) {
wp->flags &= ~PANE_INPUTOFF; wp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'd')) { if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF; wp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'T')) { if (args_has(self->args, 'T')) {
title = format_single_from_target(item, args_get(args, 'T')); pane_title = format_single(item, args_get(self->args, 'T'),
if (screen_set_title(&wp->base, title)) { c, s, wl, wp);
notify_pane("pane-title-changed", wp); if (screen_set_title(&wp->base, pane_title))
server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
} free(pane_title);
free(title);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) if (wp == w->active)
activewp = server_client_get_pane(c);
else
activewp = w->active;
if (wp == activewp)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (window_push_zoom(w, 0, args_has(args, 'Z'))) if (window_push_zoom(w, args_has(self->args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) if (window_set_active_pane(w, wp, 1)) {
server_client_set_pane(c, wp);
else if (window_set_active_pane(w, wp, 1))
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane"); cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
}
if (window_pop_zoom(w)) if (window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);

View File

@@ -84,26 +84,23 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item) cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct cmd_find_state *current = &item->shared->current;
struct client *c = cmdq_get_client(item); struct winlink *wl = item->target.wl;
struct cmd_find_state *current = cmdq_get_current(item); struct session *s = item->target.s;
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct session *s = target->s;
int next, previous, last, activity; int next, previous, last, activity;
next = (cmd_get_entry(self) == &cmd_next_window_entry); next = self->entry == &cmd_next_window_entry;
if (args_has(args, 'n')) if (args_has(self->args, 'n'))
next = 1; next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_window_entry); previous = self->entry == &cmd_previous_window_entry;
if (args_has(args, 'p')) if (args_has(self->args, 'p'))
previous = 1; previous = 1;
last = (cmd_get_entry(self) == &cmd_last_window_entry); last = self->entry == &cmd_last_window_entry;
if (args_has(args, 'l')) if (args_has(self->args, 'l'))
last = 1; last = 1;
if (next || previous || last) { if (next || previous || last) {
activity = args_has(args, 'a'); activity = args_has(self->args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window"); cmdq_error(item, "no next window");
@@ -128,7 +125,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
* If -T and select-window is invoked on same window as * If -T and select-window is invoked on same window as
* current, switch to previous window. * current, switch to previous window.
*/ */
if (args_has(args, 'T') && wl == s->curw) { if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(item, "no last window"); cmdq_error(item, "no last window");
return (-1); return (-1);
@@ -142,8 +139,6 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
} }
cmdq_insert_hook(s, item, current, "after-select-window"); cmdq_insert_hook(s, item, current, "after-select-window");
} }
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -57,42 +57,43 @@ const struct cmd_entry cmd_send_prefix_entry = {
}; };
static struct cmdq_item * static struct cmdq_item *
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after, cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
key_code key) struct cmdq_item *item, key_code key)
{ {
struct cmd_find_state *target = cmdq_get_target(item); struct session *s = fs->s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = fs->wl;
struct session *s = target->s; struct window_pane *wp = fs->wp;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&fs->wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) { if (wme == NULL || wme->mode->key_table == NULL) {
if (window_pane_key(wp, tc, s, wl, key, NULL) != 0) if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
if (window_pane_key(wp, item->client, s, wl, key, NULL) != 0)
return (NULL); return (NULL);
return (item); return (item);
} }
table = key_bindings_get_table(wme->mode->key_table(wme), 1); table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS); bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) { if (bd != NULL) {
table->references++; table->references++;
after = key_bindings_dispatch(bd, after, tc, NULL, target); item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table); key_bindings_unref_table(table);
} }
return (after); return (item);
} }
static struct cmdq_item * static struct cmdq_item *
cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after, cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
struct args *args, int i) struct cmdq_item *item, struct args *args, int i)
{ {
const char *s = args->argv[i]; const char *s = args->argv[i];
struct utf8_data *ud, *loop; struct cmdq_item *new_item;
utf8_char uc; struct utf8_data *ud, *uc;
wchar_t wc;
key_code key; key_code key;
char *endptr; char *endptr;
long n; long n;
@@ -102,49 +103,42 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
n = strtol(s, &endptr, 16); n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0') if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item); return (item);
return (cmd_send_keys_inject_key(item, after, KEYC_LITERAL|n)); return (cmd_send_keys_inject_key(c, fs, item, KEYC_LITERAL|n));
} }
literal = args_has(args, 'l'); literal = args_has(args, 'l');
if (!literal) { if (!literal) {
key = key_string_lookup_string(s); key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) { if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
after = cmd_send_keys_inject_key(item, after, key); new_item = cmd_send_keys_inject_key(c, fs, item, key);
if (after != NULL) if (new_item != NULL)
return (after); return (new_item);
} }
literal = 1; literal = 1;
} }
if (literal) { if (literal) {
ud = utf8_fromcstr(s); ud = utf8_fromcstr(s);
for (loop = ud; loop->size != 0; loop++) { for (uc = ud; uc->size != 0; uc++) {
if (loop->size == 1 && loop->data[0] <= 0x7f) if (utf8_combine(uc, &wc) != UTF8_DONE)
key = loop->data[0]; continue;
else { item = cmd_send_keys_inject_key(c, fs, item, wc);
if (utf8_from_data(loop, &uc) != UTF8_DONE)
continue;
key = uc;
}
after = cmd_send_keys_inject_key(item, after, key);
} }
free(ud); free(ud);
} }
return (after); return (item);
} }
static enum cmd_retval static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *fs = &item->target;
struct session *s = target->s; struct window_pane *wp = item->target.wp;
struct winlink *wl = target->wl; struct session *s = item->target.s;
struct window_pane *wp = target->wp; struct winlink *wl = item->target.wl;
struct key_event *event = cmdq_get_event(item); struct mouse_event *m = &item->shared->mouse;
struct mouse_event *m = &event->m;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct cmdq_item *after = item;
int i; int i;
key_code key; key_code key;
u_int np = 1; u_int np = 1;
@@ -158,7 +152,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) { if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme->mode->command == NULL) { if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode"); cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -173,7 +167,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
} }
if (!m->valid) if (!m->valid)
m = NULL; m = NULL;
wme->mode->command(wme, tc, s, wl, args, m); wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -183,29 +177,27 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target"); cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
window_pane_key(wp, tc, s, wl, m->key, m); window_pane_key(wp, item->client, s, wl, m->key, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_get_entry(self) == &cmd_send_prefix_entry) { if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2')) if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2"); key = options_get_number(s->options, "prefix2");
else else
key = options_get_number(s->options, "prefix"); key = options_get_number(s->options, "prefix");
cmd_send_keys_inject_key(item, item, key); cmd_send_keys_inject_key(c, fs, item, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'R')) { if (args_has(args, 'R')) {
window_pane_reset_palette(wp); window_pane_reset_palette(wp);
input_reset(wp->ictx, 1); input_reset(wp, 1);
} }
for (; np != 0; np--) { for (; np != 0; np--) {
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++)
after = cmd_send_keys_inject_string(item, after, args, item = cmd_send_keys_inject_string(c, fs, item, args, i);
i);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -33,11 +33,10 @@ const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer", .name = "set-buffer",
.alias = "setb", .alias = "setb",
.args = { "ab:t:n:w", 0, 1 }, .args = { "ab:n:", 0, 1 },
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] " .usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
CMD_TARGET_CLIENT_USAGE " data",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec .exec = cmd_set_buffer_exec
}; };
@@ -55,8 +54,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
static enum cmd_retval static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item);
struct paste_buffer *pb; struct paste_buffer *pb;
char *bufdata, *cause; char *bufdata, *cause;
const char *bufname, *olddata; const char *bufname, *olddata;
@@ -68,7 +66,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
else else
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) { if (self->entry == &cmd_delete_buffer_entry) {
if (pb == NULL) if (pb == NULL)
pb = paste_get_top(&bufname); pb = paste_get_top(&bufname);
if (pb == NULL) { if (pb == NULL) {
@@ -120,8 +118,6 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, bufdata, bufsize);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment", .name = "set-environment",
.alias = "setenv", .alias = "setenv",
.args = { "Fhgrt:u", 1, 2 }, .args = { "grt:u", 1, 2 },
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]", .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -46,12 +46,9 @@ const struct cmd_entry cmd_set_environment_entry = {
static enum cmd_retval static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item) cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct environ *env;
struct environ *env; const char *name, *value, *target;
const char *name, *value, *tflag;
char *expand = NULL;
enum cmd_retval retval = CMD_RETURN_NORMAL;
name = args->argv[0]; name = args->argv[0];
if (*name == '\0') { if (*name == '\0') {
@@ -65,54 +62,42 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args->argc < 2) if (args->argc < 2)
value = NULL; value = NULL;
else if (args_has(args, 'F'))
value = expand = format_single_from_target(item, args->argv[1]);
else else
value = args->argv[1]; value = args->argv[1];
if (args_has(args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (target->s == NULL) { if (item->target.s == NULL) {
tflag = args_get(args, 't'); target = args_get(args, 't');
if (tflag != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
env = target->s->environ; env = item->target.s->environ;
} }
if (args_has(args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -u"); cmdq_error(item, "can't specify a value with -u");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_unset(env, name); environ_unset(env, name);
} else if (args_has(args, 'r')) { } else if (args_has(self->args, 'r')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -r"); cmdq_error(item, "can't specify a value with -r");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_clear(env, name); environ_clear(env, name);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "no value specified"); cmdq_error(item, "no value specified");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_set(env, name, "%s", value);
if (args_has(args, 'h'))
environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
else
environ_set(env, name, 0, "%s", value);
} }
out: return (CMD_RETURN_NORMAL);
free(expand);
return (retval);
} }

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -29,12 +30,21 @@
static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
static int cmd_set_option_choice(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
.name = "set-option", .name = "set-option",
.alias = "set", .alias = "set",
.args = { "aFgopqst:uUw", 1, 2 }, .args = { "aFgopqst:uw", 1, 2 },
.usage = "[-aFgopqsuUw] " CMD_TARGET_PANE_USAGE " option [value]", .usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -59,10 +69,10 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook", .name = "set-hook",
.alias = NULL, .alias = NULL,
.args = { "agpRt:uw", 1, 2 }, .args = { "agRt:u", 1, 2 },
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]", .usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
@@ -71,23 +81,29 @@ const struct cmd_entry cmd_set_hook_entry = {
static enum cmd_retval static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
int append = args_has(args, 'a'); int append = args_has(args, 'a');
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *fs = &item->target;
struct window_pane *loop; struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
struct window_pane *wp;
struct options *oo; struct options *oo;
struct options_entry *parent, *o, *po; struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause; char *name, *argument, *value = NULL, *cause;
int window, idx, already, error, ambiguous; int window, idx, already, error, ambiguous;
int scope; int scope;
struct style *sy;
window = (cmd_get_entry(self) == &cmd_set_window_option_entry); window = (self->entry == &cmd_set_window_option_entry);
/* Expand argument. */ /* Expand argument. */
argument = format_single_from_target(item, args->argv[0]); c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
/* If set-hook -R, fire the hook straight away. */ /* If set-hook -R, fire the hook straight away. */
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) { if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument); notify_hook(item, argument);
free(argument); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -107,13 +123,12 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (args->argc < 2) if (args->argc < 2)
value = NULL; value = NULL;
else if (args_has(args, 'F')) else if (args_has(args, 'F'))
value = format_single_from_target(item, args->argv[1]); value = format_single(item, args->argv[1], c, s, wl, NULL);
else else
value = xstrdup(args->argv[1]); value = xstrdup(args->argv[1]);
/* Get the scope and table for the option .*/ /* Get the scope and table for the option .*/
scope = options_scope_from_name(args, window, name, target, &oo, scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto out; goto out;
@@ -125,7 +140,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name); parent = options_get(oo, name);
/* Check that array options and indexes match up. */ /* Check that array options and indexes match up. */
if (idx != -1 && (*name == '@' || !options_is_array(parent))) { if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
cmdq_error(item, "not an array: %s", argument); cmdq_error(item, "not an array: %s", argument);
goto fail; goto fail;
} }
@@ -149,22 +164,19 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} }
/* Change the option. */ /* Change the option. */
if (args_has(args, 'U') && scope == OPTIONS_TABLE_WINDOW) { if (args_has(args, 'u')) {
TAILQ_FOREACH(loop, &target->w->panes, entry) {
po = options_get_only(loop->options, name);
if (po == NULL)
continue;
if (options_remove_or_default(po, idx, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
}
}
if (args_has(args, 'u') || args_has(args, 'U')) {
if (o == NULL) if (o == NULL)
goto out; goto out;
if (options_remove_or_default(o, idx, &cause) != 0) { if (idx == -1) {
if (*name == '@')
options_remove(o);
else if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
else
options_remove(o);
} else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
goto fail; goto fail;
@@ -175,15 +187,10 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_is_array(parent)) { } else if (idx == -1 && !options_isarray(parent)) {
error = options_from_string(oo, options_table_entry(parent), error = cmd_set_option_set(self, item, oo, parent, value);
options_table_entry(parent)->name, value, if (error != 0)
args_has(args, 'a'), &cause);
if (error != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail; goto fail;
}
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "empty value"); cmdq_error(item, "empty value");
@@ -207,7 +214,61 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
options_push_changes(name); /* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
sy = options_get_style(oo, "status-style");
sy->gc.fg = options_get_number(oo, "status-fg");
sy->gc.bg = options_get_number(oo, "status-bg");
}
if (strcmp(name, "status-style") == 0) {
sy = options_get_style(oo, "status-style");
options_set_number(oo, "status-fg", sy->gc.fg);
options_set_number(oo, "status-bg", sy->gc.bg);
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w);
}
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
out: out:
free(argument); free(argument);
@@ -221,3 +282,130 @@ fail:
free(name); free(name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
struct args *args = self->args;
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr, *new;
char *old;
key_code key;
oe = options_table_entry(parent);
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
cmdq_error(item, "empty value");
return (-1);
}
switch (oe->type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_STYLE:
o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
return (0);
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);
}
static int
cmd_set_option_flag(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(item, "bad value: %s", value);
return (-1);
}
options_set_number(oo, oe->name, flag);
return (0);
}
static int
cmd_set_option_choice(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
return (-1);
}
}
options_set_number(oo, oe->name, choice);
return (0);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment", .name = "show-environment",
.alias = "showenv", .alias = "showenv",
.args = { "hgst:", 0, 1 }, .args = { "gst:", 0, 1 },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]", .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -69,15 +69,9 @@ static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item, cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent) struct environ_entry *envent)
{ {
struct args *args = cmd_get_args(self); char *escaped;
char *escaped;
if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN)) if (!args_has(self->args, 's')) {
return;
if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
return;
if (!args_has(args, 's')) {
if (envent->value != NULL) if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value); cmdq_print(item, "%s=%s", envent->name, envent->value);
else else
@@ -97,31 +91,30 @@ cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
static enum cmd_retval static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item) cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct environ *env; struct environ *env;
struct environ_entry *envent; struct environ_entry *envent;
const char *tflag; const char *target;
if ((tflag = args_get(args, 't')) != NULL) { if ((target = args_get(args, 't')) != NULL) {
if (target->s == NULL) { if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
if (args_has(args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (target->s == NULL) { if (item->target.s == NULL) {
tflag = args_get(args, 't'); target = args_get(args, 't');
if (tflag != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = target->s->environ; env = item->target.s->environ;
} }
if (args->argc != 0) { if (args->argc != 0) {

View File

@@ -18,19 +18,16 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Show message log. * Show client message log.
*/ */
#define SHOW_MESSAGES_TEMPLATE \
"#{t/p:message_time}: #{message_text}"
static enum cmd_retval cmd_show_messages_exec(struct cmd *, static enum cmd_retval cmd_show_messages_exec(struct cmd *,
struct cmdq_item *); struct cmdq_item *);
@@ -41,28 +38,26 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 }, .args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE, .usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec .exec = cmd_show_messages_exec
}; };
static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int static int
cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank) cmd_show_messages_terminals(struct cmdq_item *item, int blank)
{ {
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct tty_term *term; struct tty_term *term;
u_int i, n; u_int i, n;
n = 0; n = 0;
LIST_FOREACH(term, &tty_terms, entry) { LIST_FOREACH(term, &tty_terms, entry) {
if (args_has(args, 't') && term != tc->tty.term)
continue;
if (blank) { if (blank) {
cmdq_print(item, "%s", ""); cmdq_print(item, "%s", "");
blank = 0; blank = 0;
} }
cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n, cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
term->name, term->tty->client->name, term->flags); n, term->name, term->references, term->flags);
n++; n++;
for (i = 0; i < tty_term_ncodes(); i++) for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(item, "%s", tty_term_describe(term, i)); cmdq_print(item, "%s", tty_term_describe(term, i));
@@ -73,15 +68,18 @@ cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank)
static enum cmd_retval static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item) cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *s; char *tim;
int done, blank; int done, blank;
struct format_tree *ft;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0; done = blank = 0;
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(self, item, blank); blank = cmd_show_messages_terminals(item, blank);
done = 1; done = 1;
} }
if (args_has(args, 'J')) { if (args_has(args, 'J')) {
@@ -91,17 +89,12 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
if (done) if (done)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
ft = format_create_from_target(item); TAILQ_FOREACH(msg, &c->message_log, entry) {
TAILQ_FOREACH_REVERSE(msg, &message_log, message_list, entry) { tim = ctime(&msg->msg_time);
format_add(ft, "message_text", "%s", msg->msg); *strchr(tim, '\n') = '\0';
format_add(ft, "message_number", "%u", msg->msg_num);
format_add_tv(ft, "message_time", &msg->msg_time);
s = format_expand(ft, SHOW_MESSAGES_TEMPLATE); cmdq_print(item, "%s %s", tim, msg->msg);
cmdq_print(item, "%s", s);
free(s);
} }
format_free(ft);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -64,10 +64,10 @@ const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks", .name = "show-hooks",
.alias = NULL, .alias = NULL,
.args = { "gpt:w", 0, 1 }, .args = { "gt:", 0, 1 },
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE, .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
@@ -76,18 +76,20 @@ const struct cmd_entry cmd_show_hooks_entry = {
static enum cmd_retval static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *fs = &item->target;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options *oo; struct options *oo;
char *argument, *name = NULL, *cause; char *argument, *name = NULL, *cause;
int window, idx, ambiguous, parent, scope; int window, idx, ambiguous, parent, scope;
struct options_entry *o; struct options_entry *o;
window = (cmd_get_entry(self) == &cmd_show_window_options_entry); window = (self->entry == &cmd_show_window_options_entry);
if (args->argc == 0) { if (args->argc == 0) {
scope = options_scope_from_flags(args, window, target, &oo, scope = options_scope_from_flags(args, window, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -97,7 +99,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
} }
return (cmd_show_options_all(self, item, scope, oo)); return (cmd_show_options_all(self, item, scope, oo));
} }
argument = format_single_from_target(item, args->argv[0]); argument = format_single(item, args->argv[0], c, s, wl, NULL);
name = options_match(argument, &idx, &ambiguous); name = options_match(argument, &idx, &ambiguous);
if (name == NULL) { if (name == NULL) {
@@ -109,8 +111,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid option: %s", argument); cmdq_error(item, "invalid option: %s", argument);
goto fail; goto fail;
} }
scope = options_scope_from_name(args, window, name, target, &oo, scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto fail; goto fail;
@@ -141,7 +142,6 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item, cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx, int parent) struct options_entry *o, int idx, int parent)
{ {
struct args *args = cmd_get_args(self);
struct options_array_item *a; struct options_array_item *a;
const char *name = options_name(o); const char *name = options_name(o);
char *value, *tmp = NULL, *escaped; char *value, *tmp = NULL, *escaped;
@@ -150,10 +150,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
xasprintf(&tmp, "%s[%d]", name, idx); xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp; name = tmp;
} else { } else {
if (options_is_array(o)) { if (options_isarray(o)) {
a = options_array_first(o); a = options_array_first(o);
if (a == NULL) { if (a == NULL) {
if (!args_has(args, 'v')) if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", name); cmdq_print(item, "%s", name);
return; return;
} }
@@ -167,10 +167,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
} }
} }
value = options_to_string(o, idx, 0); value = options_tostring(o, idx, 0);
if (args_has(args, 'v')) if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value); cmdq_print(item, "%s", value);
else if (options_is_string(o)) { else if (options_isstring(o)) {
escaped = args_escape(value); escaped = args_escape(value);
if (parent) if (parent)
cmdq_print(item, "%s* %s", name, escaped); cmdq_print(item, "%s* %s", name, escaped);
@@ -192,7 +192,6 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope, cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo) struct options *oo)
{ {
struct args *args = cmd_get_args(self);
const struct options_table_entry *oe; const struct options_table_entry *oe;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
@@ -200,28 +199,28 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
u_int idx; u_int idx;
int parent; int parent;
if (cmd_get_entry(self) != &cmd_show_hooks_entry) { o = options_first(oo);
o = options_first(oo); while (o != NULL) {
while (o != NULL) { if (options_table_entry(o) == NULL)
if (options_table_entry(o) == NULL) cmd_show_options_print(self, item, o, -1, 0);
cmd_show_options_print(self, item, o, -1, 0); o = options_next(o);
o = options_next(o);
}
} }
for (oe = options_table; oe->name != NULL; oe++) { for (oe = options_table; oe->name != NULL; oe++) {
if (~oe->scope & scope) if (~oe->scope & scope)
continue; continue;
if ((cmd_get_entry(self) != &cmd_show_hooks_entry && if ((self->entry != &cmd_show_hooks_entry &&
!args_has(args, 'H') && !args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) || (oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(cmd_get_entry(self) == &cmd_show_hooks_entry && (self->entry == &cmd_show_hooks_entry &&
(~oe->flags & OPTIONS_TABLE_IS_HOOK))) (oe == NULL ||
(~oe->flags & OPTIONS_TABLE_IS_HOOK))))
continue; continue;
o = options_get_only(oo, oe->name); o = options_get_only(oo, oe->name);
if (o == NULL) { if (o == NULL) {
if (!args_has(args, 'A')) if (!args_has(self->args, 'A'))
continue; continue;
o = options_get(oo, oe->name); o = options_get(oo, oe->name);
if (o == NULL) if (o == NULL)
@@ -230,10 +229,10 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
} else } else
parent = 0; parent = 0;
if (!options_is_array(o)) if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1, parent); cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) { else if ((a = options_array_first(o)) == NULL) {
if (!args_has(args, 'v')) { if (!args_has(self->args, 'v')) {
name = options_name(o); name = options_name(o);
if (parent) if (parent)
cmdq_print(item, "%s*", name); cmdq_print(item, "%s*", name);

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_source_file_entry = {
.name = "source-file", .name = "source-file",
.alias = "source", .alias = "source",
.args = { "Fnqv", 1, -1 }, .args = { "nqv", 1, -1 },
.usage = "[-Fnqv] path ...", .usage = "[-nqv] path ...",
.flags = 0, .flags = 0,
.exec = cmd_source_file_exec .exec = cmd_source_file_exec
@@ -122,11 +122,11 @@ cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
static enum cmd_retval static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item) cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_source_file_data *cdata; struct cmd_source_file_data *cdata;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
enum cmd_retval retval = CMD_RETURN_NORMAL; enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd, *expand = NULL; char *pattern, *cwd;
const char *path, *error; const char *path, *error;
glob_t g; glob_t g;
int i, result; int i, result;
@@ -145,12 +145,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB); utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++) {
if (args_has(args, 'F')) { path = args->argv[i];
free(expand);
expand = format_single_from_target(item, args->argv[i]);
path = expand;
} else
path = args->argv[i];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cmd_source_file_add(cdata, "-"); cmd_source_file_add(cdata, "-");
continue; continue;
@@ -177,7 +172,6 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
free(pattern); free(pattern);
continue; continue;
} }
free(expand);
free(pattern); free(pattern);
for (j = 0; j < g.gl_pathc; j++) for (j = 0; j < g.gl_pathc; j++)

View File

@@ -39,8 +39,8 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window", .name = "split-window",
.alias = "splitw", .alias = "splitw",
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1 }, .args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " .usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]", "[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -52,14 +52,13 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc; struct spawn_context sc;
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = item->target.s;
struct winlink *wl = target->wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = target->wp, *new_wp; struct window_pane *wp = item->target.wp, *new_wp;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct cmd_find_state fs; struct cmd_find_state fs;
@@ -110,7 +109,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} else } else
size = -1; size = -1;
window_push_zoom(wp->window, 1, args_has(args, 'Z')); server_unzoom_window(wp->window);
input = (args_has(args, 'I') && args->argc == 0); input = (args_has(args, 'I') && args->argc == 0);
flags = 0; flags = 0;
@@ -142,7 +141,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value); add = args_first_value(args, 'e', &value);
while (add != NULL) { while (add != NULL) {
environ_put(sc.environ, add, 0); environ_put(sc.environ, add);
add = args_next_value(&value); add = args_next_value(&value);
} }
@@ -152,8 +151,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.flags = flags; sc.flags = flags;
if (args_has(args, 'd')) if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED; sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'Z'))
sc.flags |= SPAWN_ZOOM;
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
cmdq_error(item, "create pane failed: %s", cause); cmdq_error(item, "create pane failed: %s", cause);
@@ -161,7 +158,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (input && window_pane_start_input(new_wp, item, &cause) != 0) { if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
server_client_remove_pane(new_wp);
layout_close_pane(new_wp); layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp); window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
@@ -170,14 +166,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} }
if (!args_has(args, 'd')) if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0); cmd_find_from_winlink_pane(current, wl, new_wp, 0);
window_pop_zoom(wp->window);
server_redraw_window(wp->window); server_redraw_window(wp->window);
server_status_session(s); server_status_session(s);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE; template = SPLIT_WINDOW_TEMPLATE;
cp = format_single(item, template, tc, s, wl, new_wp); cp = format_single(item, template, c, s, wl, new_wp);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }

View File

@@ -45,20 +45,18 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
dst_w = target->wl->window; dst_w = item->target.wl->window;
dst_wp = target->wp; dst_wp = item->target.wp;
src_w = source->wl->window; src_w = item->source.wl->window;
src_wp = source->wp; src_wp = item->source.wp;
if (window_push_zoom(dst_w, 0, args_has(args, 'Z'))) if (window_push_zoom(dst_w, args_has(args, 'Z')))
server_redraw_window(dst_w); server_redraw_window(dst_w);
if (args_has(args, 'D')) { if (args_has(args, 'D')) {
@@ -73,15 +71,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes); src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
} }
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z'))) if (src_w != dst_w && window_push_zoom(src_w, args_has(args, 'Z')))
server_redraw_window(src_w); server_redraw_window(src_w);
if (src_wp == dst_wp) if (src_wp == dst_wp)
goto out; goto out;
server_client_remove_pane(src_wp);
server_client_remove_pane(dst_wp);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry); TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry);

View File

@@ -45,20 +45,20 @@ const struct cmd_entry cmd_swap_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct session *src, *dst;
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *src = source->s, *dst = target->s;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src = source->wl, *wl_dst = target->wl; struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst; struct window *w_src, *w_dst;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src); sg_src = session_group_contains(src);
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst); sg_dst = session_group_contains(dst);
if (src != dst && if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src != NULL &&
sg_dst != NULL &&
sg_src == sg_dst) { sg_src == sg_dst) {
cmdq_error(item, "can't move window, sessions are grouped"); cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -77,7 +77,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src->window = w_dst; wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry); TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (args_has(args, 'd')) { if (args_has(self->args, 'd')) {
session_select(dst, wl_dst->idx); session_select(dst, wl_dst->idx);
if (src != dst) if (src != dst)
session_select(src, wl_src->idx); session_select(src, wl_src->idx);

View File

@@ -34,26 +34,24 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client", .name = "switch-client",
.alias = "switchc", .alias = "switchc",
.args = { "lc:EFnpt:rT:Z", 0, 0 }, .args = { "lc:Enpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] " .usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]", "[-T key-table]",
/* -t is special */ /* -t is special */
.flags = CMD_READONLY|CMD_CLIENT_CFLAG, .flags = CMD_READONLY,
.exec = cmd_switch_client_exec .exec = cmd_switch_client_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
const char *tflag = args_get(args, 't'); const char *tflag = args_get(args, 't');
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
@@ -61,6 +59,9 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
const char *tablename; const char *tablename;
struct key_table *table; struct key_table *table;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') { if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE; type = CMD_FIND_PANE;
flags = 0; flags = 0;
@@ -68,18 +69,15 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
type = CMD_FIND_SESSION; type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED; flags = CMD_FIND_PREFER_UNATTACHED;
} }
if (cmd_find_target(&target, item, tflag, type, flags) != 0) if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
s = target.s; s = item->target.s;
wl = target.wl; wl = item->target.wl;
wp = target.wp; w = wl->window;
wp = item->target.wp;
if (args_has(args, 'r')) { if (args_has(args, 'r'))
if (tc->flags & CLIENT_READONLY) c->flags ^= CLIENT_READONLY;
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename != NULL) { if (tablename != NULL) {
@@ -89,24 +87,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
table->references++; table->references++;
key_bindings_unref_table(tc->keytable); key_bindings_unref_table(c->keytable);
tc->keytable = table; c->keytable = table;
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if ((s = session_next_session(tc->session)) == NULL) { if ((s = session_next_session(c->session)) == NULL) {
cmdq_error(item, "can't find next session"); cmdq_error(item, "can't find next session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
if ((s = session_previous_session(tc->session)) == NULL) { if ((s = session_previous_session(c->session)) == NULL) {
cmdq_error(item, "can't find previous session"); cmdq_error(item, "can't find previous session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'l')) { } else if (args_has(args, 'l')) {
if (tc->last_session != NULL && session_alive(tc->last_session)) if (c->last_session != NULL && session_alive(c->last_session))
s = tc->last_session; s = c->last_session;
else else
s = NULL; s = NULL;
if (s == NULL) { if (s == NULL) {
@@ -114,11 +112,10 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (cmdq_get_client(item) == NULL) if (item->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) { if (wl != NULL && wp != NULL) {
w = wl->window; if (window_push_zoom(w, args_has(self->args, 'Z')))
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
@@ -127,28 +124,28 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} }
if (wl != NULL) { if (wl != NULL) {
session_set_current(s, wl); session_set_current(s, wl);
cmd_find_from_session(current, s, 0); cmd_find_from_session(&item->shared->current, s, 0);
} }
} }
if (!args_has(args, 'E')) if (!args_has(args, 'E'))
environ_update(s->options, tc->environ, s->environ); environ_update(s->options, c->environ, s->environ);
if (tc->session != NULL && tc->session != s) if (c->session != NULL && c->session != s)
tc->last_session = tc->session; c->last_session = c->session;
tc->session = s; c->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(tc, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(tc); tty_update_client_offset(c);
status_timer_start(tc); status_timer_start(c);
notify_client("client-session-changed", tc); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
server_check_unattached(); server_check_unattached();
server_redraw_client(tc); server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = tc; s->curw->window->latest = c;
recalculate_sizes(); recalculate_sizes();
alerts_check_session(s); alerts_check_session(s);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key", .name = "unbind-key",
.alias = "unbind", .alias = "unbind",
.args = { "anqT:", 0, 1 }, .args = { "anT:", 0, 1 },
.usage = "[-anq] [-T key-table] key", .usage = "[-an] [-T key-table] key",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_unbind_key_exec .exec = cmd_unbind_key_exec
@@ -42,57 +42,47 @@ const struct cmd_entry cmd_unbind_key_entry = {
static enum cmd_retval static enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
key_code key; key_code key;
const char *tablename; const char *tablename;
int quiet = args_has(args, 'q');
if (args_has(args, 'a')) { if (!args_has(args, 'a')) {
if (args->argc != 0) { if (args->argc != 1) {
if (!quiet) cmdq_error(item, "missing key");
cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
} else {
if (args->argc != 0) {
cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR);
}
key = KEYC_UNKNOWN;
}
if (key == KEYC_UNKNOWN) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename == NULL) { if (tablename == NULL) {
if (args_has(args, 'n')) key_bindings_remove_table("root");
tablename = "root"; key_bindings_remove_table("prefix");
else return (CMD_RETURN_NORMAL);
tablename = "prefix";
} }
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
if (!quiet) { cmdq_error(item, "table %s doesn't exist", tablename);
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key_bindings_remove_table(tablename); key_bindings_remove_table(tablename);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args->argc != 1) {
if (!quiet)
cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR);
}
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
if (!quiet)
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
if (!quiet) { cmdq_error(item, "table %s doesn't exist", tablename);
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'n')) } else if (args_has(args, 'n'))

View File

@@ -120,7 +120,7 @@ cmd_wait_for_remove(struct wait_channel *wc)
static enum cmd_retval static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item) cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
const char *name = args->argv[0]; const char *name = args->argv[0];
struct wait_channel *wc, wc0; struct wait_channel *wc, wc0;
@@ -167,7 +167,7 @@ static enum cmd_retval
cmd_wait_for_wait(struct cmdq_item *item, const char *name, cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct wait_item *wi; struct wait_item *wi;
if (c == NULL) { if (c == NULL) {
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{ {
struct wait_item *wi; struct wait_item *wi;
if (cmdq_get_client(item) == NULL) { if (item->client == NULL) {
cmdq_error(item, "not able to lock"); cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

170
cmd.c
View File

@@ -39,12 +39,10 @@ extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry; extern const struct cmd_entry cmd_command_prompt_entry;
extern const struct cmd_entry cmd_confirm_before_entry; extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_customize_mode_entry;
extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_detach_client_entry;
extern const struct cmd_entry cmd_display_menu_entry; extern const struct cmd_entry cmd_display_menu_entry;
extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_popup_entry;
extern const struct cmd_entry cmd_display_panes_entry; extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_down_pane_entry;
extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_find_window_entry;
@@ -130,12 +128,10 @@ const struct cmd_entry *cmd_table[] = {
&cmd_command_prompt_entry, &cmd_command_prompt_entry,
&cmd_confirm_before_entry, &cmd_confirm_before_entry,
&cmd_copy_mode_entry, &cmd_copy_mode_entry,
&cmd_customize_mode_entry,
&cmd_delete_buffer_entry, &cmd_delete_buffer_entry,
&cmd_detach_client_entry, &cmd_detach_client_entry,
&cmd_display_menu_entry, &cmd_display_menu_entry,
&cmd_display_message_entry, &cmd_display_message_entry,
&cmd_display_popup_entry,
&cmd_display_panes_entry, &cmd_display_panes_entry,
&cmd_find_window_entry, &cmd_find_window_entry,
&cmd_has_session_entry, &cmd_has_session_entry,
@@ -208,27 +204,8 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
/* Instance of a command. */
struct cmd {
const struct cmd_entry *entry;
struct args *args;
u_int group;
char *file;
u_int line;
char *alias;
int argc;
char **argv;
TAILQ_ENTRY(cmd) qentry;
};
TAILQ_HEAD(cmds, cmd);
/* Next group number for new command list. */
static u_int cmd_list_next_group = 1; static u_int cmd_list_next_group = 1;
/* Log an argument vector. */
void printflike(3, 4) void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...) cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{ {
@@ -245,7 +222,6 @@ cmd_log_argv(int argc, char **argv, const char *fmt, ...)
free(prefix); free(prefix);
} }
/* Prepend to an argument vector. */
void void
cmd_prepend_argv(int *argc, char ***argv, char *arg) cmd_prepend_argv(int *argc, char ***argv, char *arg)
{ {
@@ -262,7 +238,6 @@ cmd_prepend_argv(int *argc, char ***argv, char *arg)
(*argc)++; (*argc)++;
} }
/* Append to an argument vector. */
void void
cmd_append_argv(int *argc, char ***argv, char *arg) cmd_append_argv(int *argc, char ***argv, char *arg)
{ {
@@ -270,7 +245,6 @@ cmd_append_argv(int *argc, char ***argv, char *arg)
(*argv)[(*argc)++] = xstrdup(arg); (*argv)[(*argc)++] = xstrdup(arg);
} }
/* Pack an argument vector up into a buffer. */
int int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len) cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{ {
@@ -293,7 +267,6 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
return (0); return (0);
} }
/* Unpack an argument vector from a packed buffer. */
int int
cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
{ {
@@ -322,7 +295,6 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0); return (0);
} }
/* Copy an argument vector, ensuring it is terminated by NULL. */
char ** char **
cmd_copy_argv(int argc, char **argv) cmd_copy_argv(int argc, char **argv)
{ {
@@ -339,7 +311,6 @@ cmd_copy_argv(int argc, char **argv)
return (new_argv); return (new_argv);
} }
/* Free an argument vector. */
void void
cmd_free_argv(int argc, char **argv) cmd_free_argv(int argc, char **argv)
{ {
@@ -352,67 +323,32 @@ cmd_free_argv(int argc, char **argv)
free(argv); free(argv);
} }
/* Convert argument vector to a string. */
char * char *
cmd_stringify_argv(int argc, char **argv) cmd_stringify_argv(int argc, char **argv)
{ {
char *buf = NULL, *s; char *buf;
size_t len = 0;
int i; int i;
size_t len;
if (argc == 0) if (argc == 0)
return (xstrdup("")); return (xstrdup(""));
for (i = 0; i < argc; i++) { len = 0;
s = args_escape(argv[i]); buf = NULL;
log_debug("%s: %u %s = %s", __func__, i, argv[i], s);
len += strlen(s) + 1; for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1;
buf = xrealloc(buf, len); buf = xrealloc(buf, len);
if (i == 0) if (i == 0)
*buf = '\0'; *buf = '\0';
else else
strlcat(buf, " ", len); strlcat(buf, " ", len);
strlcat(buf, s, len); strlcat(buf, argv[i], len);
free(s);
} }
return (buf); return (buf);
} }
/* Get entry for command. */
const struct cmd_entry *
cmd_get_entry(struct cmd *cmd)
{
return (cmd->entry);
}
/* Get arguments for command. */
struct args *
cmd_get_args(struct cmd *cmd)
{
return (cmd->args);
}
/* Get group for command. */
u_int
cmd_get_group(struct cmd *cmd)
{
return (cmd->group);
}
/* Get file and line for command. */
void
cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
{
if (file != NULL)
*file = cmd->file;
if (line != NULL)
*line = cmd->line;
}
/* Look for an alias for a command. */
char * char *
cmd_get_alias(const char *name) cmd_get_alias(const char *name)
{ {
@@ -443,7 +379,6 @@ cmd_get_alias(const char *name)
return (NULL); return (NULL);
} }
/* Look up a command entry by name. */
static const struct cmd_entry * static const struct cmd_entry *
cmd_find(const char *name, char **cause) cmd_find(const char *name, char **cause)
{ {
@@ -493,7 +428,6 @@ ambiguous:
return (NULL); return (NULL);
} }
/* Parse a single command from an argument vector. */
struct cmd * struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{ {
@@ -542,7 +476,6 @@ usage:
return (NULL); return (NULL);
} }
/* Free a command. */
void void
cmd_free(struct cmd *cmd) cmd_free(struct cmd *cmd)
{ {
@@ -555,7 +488,6 @@ cmd_free(struct cmd *cmd)
free(cmd); free(cmd);
} }
/* Get a command as a string. */
char * char *
cmd_print(struct cmd *cmd) cmd_print(struct cmd *cmd)
{ {
@@ -571,7 +503,6 @@ cmd_print(struct cmd *cmd)
return (out); return (out);
} }
/* Create a new command list. */
struct cmd_list * struct cmd_list *
cmd_list_new(void) cmd_list_new(void)
{ {
@@ -580,28 +511,29 @@ cmd_list_new(void)
cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1; cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++; cmdlist->group = cmd_list_next_group++;
cmdlist->list = xcalloc(1, sizeof *cmdlist->list); TAILQ_INIT(&cmdlist->list);
TAILQ_INIT(cmdlist->list);
return (cmdlist); return (cmdlist);
} }
/* Append a command to a command list. */
void void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd) cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{ {
cmd->group = cmdlist->group; cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
} }
/* Move all commands from one command list to another */
void void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from) cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{ {
TAILQ_CONCAT(cmdlist->list, from->list, qentry); 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++; cmdlist->group = cmd_list_next_group++;
} }
/* Free a command list. */
void void
cmd_list_free(struct cmd_list *cmdlist) cmd_list_free(struct cmd_list *cmdlist)
{ {
@@ -610,46 +542,36 @@ cmd_list_free(struct cmd_list *cmdlist)
if (--cmdlist->references != 0) if (--cmdlist->references != 0)
return; return;
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) { TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(cmdlist->list, cmd, qentry); TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd); cmd_free(cmd);
} }
free(cmdlist->list);
free(cmdlist); free(cmdlist);
} }
/* Get a command list as a string. */
char * char *
cmd_list_print(struct cmd_list *cmdlist, int escaped) cmd_list_print(struct cmd_list *cmdlist, int escaped)
{ {
struct cmd *cmd, *next; struct cmd *cmd;
char *buf, *this; char *buf, *this;
size_t len; size_t len;
len = 1; len = 1;
buf = xcalloc(1, len); buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd); this = cmd_print(cmd);
len += strlen(this) + 6; len += strlen(this) + 4;
buf = xrealloc(buf, len); buf = xrealloc(buf, len);
strlcat(buf, this, len); strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) {
next = TAILQ_NEXT(cmd, qentry); if (escaped)
if (next != NULL) { strlcat(buf, " \\; ", len);
if (cmd->group != next->group) { else
if (escaped) strlcat(buf, " ; ", len);
strlcat(buf, " \\;\\; ", len);
else
strlcat(buf, " ;; ", len);
} else {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
} }
free(this); free(this);
@@ -658,46 +580,6 @@ cmd_list_print(struct cmd_list *cmdlist, int escaped)
return (buf); return (buf);
} }
/* Get first command in list. */
struct cmd *
cmd_list_first(struct cmd_list *cmdlist)
{
return (TAILQ_FIRST(cmdlist->list));
}
/* Get next command in list. */
struct cmd *
cmd_list_next(struct cmd *cmd)
{
return (TAILQ_NEXT(cmd, qentry));
}
/* Do all of the commands in this command list have this flag? */
int
cmd_list_all_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (~cmd->entry->flags & flag)
return (0);
}
return (1);
}
/* Do any of the commands in this command list have this flag? */
int
cmd_list_any_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (cmd->entry->flags & flag)
return (1);
}
return (0);
}
/* Adjust current mouse position for a pane. */ /* Adjust current mouse position for a pane. */
int int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp, cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,

617
colour.c
View File

@@ -22,7 +22,6 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h>
#include "tmux.h" #include "tmux.h"
@@ -112,9 +111,6 @@ colour_tostring(int c)
static char s[32]; static char s[32];
u_char r, g, b; u_char r, g, b;
if (c == -1)
return ("invalid");
if (c & COLOUR_FLAG_RGB) { if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b); colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b); xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
@@ -193,12 +189,6 @@ colour_fromstring(const char *s)
return (-1); return (-1);
return (n | COLOUR_FLAG_256); return (n | COLOUR_FLAG_256);
} }
if (strncasecmp(s, "color", (sizeof "color") - 1) == 0) {
n = strtonum(s + (sizeof "color") - 1, 0, 255, &errstr);
if (errstr != NULL)
return (-1);
return (n | COLOUR_FLAG_256);
}
if (strcasecmp(s, "default") == 0) if (strcasecmp(s, "default") == 0)
return (8); return (8);
@@ -237,7 +227,7 @@ colour_fromstring(const char *s)
return (96); return (96);
if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0) if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
return (97); return (97);
return (colour_byname(s)); return (-1);
} }
/* Convert 256 colour to RGB colour. */ /* Convert 256 colour to RGB colour. */
@@ -339,608 +329,3 @@ colour_256to16(int c)
return (table[c & 0xff]); return (table[c & 0xff]);
} }
/* Get colour by X11 colour name. */
int
colour_byname(const char *name)
{
static const struct {
const char *name;
int c;
} colours[] = {
{ "AliceBlue", 0xf0f8ff },
{ "AntiqueWhite", 0xfaebd7 },
{ "AntiqueWhite1", 0xffefdb },
{ "AntiqueWhite2", 0xeedfcc },
{ "AntiqueWhite3", 0xcdc0b0 },
{ "AntiqueWhite4", 0x8b8378 },
{ "BlanchedAlmond", 0xffebcd },
{ "BlueViolet", 0x8a2be2 },
{ "CadetBlue", 0x5f9ea0 },
{ "CadetBlue1", 0x98f5ff },
{ "CadetBlue2", 0x8ee5ee },
{ "CadetBlue3", 0x7ac5cd },
{ "CadetBlue4", 0x53868b },
{ "CornflowerBlue", 0x6495ed },
{ "DarkBlue", 0x00008b },
{ "DarkCyan", 0x008b8b },
{ "DarkGoldenrod", 0xb8860b },
{ "DarkGoldenrod1", 0xffb90f },
{ "DarkGoldenrod2", 0xeead0e },
{ "DarkGoldenrod3", 0xcd950c },
{ "DarkGoldenrod4", 0x8b6508 },
{ "DarkGray", 0xa9a9a9 },
{ "DarkGreen", 0x006400 },
{ "DarkGrey", 0xa9a9a9 },
{ "DarkKhaki", 0xbdb76b },
{ "DarkMagenta", 0x8b008b },
{ "DarkOliveGreen", 0x556b2f },
{ "DarkOliveGreen1", 0xcaff70 },
{ "DarkOliveGreen2", 0xbcee68 },
{ "DarkOliveGreen3", 0xa2cd5a },
{ "DarkOliveGreen4", 0x6e8b3d },
{ "DarkOrange", 0xff8c00 },
{ "DarkOrange1", 0xff7f00 },
{ "DarkOrange2", 0xee7600 },
{ "DarkOrange3", 0xcd6600 },
{ "DarkOrange4", 0x8b4500 },
{ "DarkOrchid", 0x9932cc },
{ "DarkOrchid1", 0xbf3eff },
{ "DarkOrchid2", 0xb23aee },
{ "DarkOrchid3", 0x9a32cd },
{ "DarkOrchid4", 0x68228b },
{ "DarkRed", 0x8b0000 },
{ "DarkSalmon", 0xe9967a },
{ "DarkSeaGreen", 0x8fbc8f },
{ "DarkSeaGreen1", 0xc1ffc1 },
{ "DarkSeaGreen2", 0xb4eeb4 },
{ "DarkSeaGreen3", 0x9bcd9b },
{ "DarkSeaGreen4", 0x698b69 },
{ "DarkSlateBlue", 0x483d8b },
{ "DarkSlateGray", 0x2f4f4f },
{ "DarkSlateGray1", 0x97ffff },
{ "DarkSlateGray2", 0x8deeee },
{ "DarkSlateGray3", 0x79cdcd },
{ "DarkSlateGray4", 0x528b8b },
{ "DarkSlateGrey", 0x2f4f4f },
{ "DarkTurquoise", 0x00ced1 },
{ "DarkViolet", 0x9400d3 },
{ "DeepPink", 0xff1493 },
{ "DeepPink1", 0xff1493 },
{ "DeepPink2", 0xee1289 },
{ "DeepPink3", 0xcd1076 },
{ "DeepPink4", 0x8b0a50 },
{ "DeepSkyBlue", 0x00bfff },
{ "DeepSkyBlue1", 0x00bfff },
{ "DeepSkyBlue2", 0x00b2ee },
{ "DeepSkyBlue3", 0x009acd },
{ "DeepSkyBlue4", 0x00688b },
{ "DimGray", 0x696969 },
{ "DimGrey", 0x696969 },
{ "DodgerBlue", 0x1e90ff },
{ "DodgerBlue1", 0x1e90ff },
{ "DodgerBlue2", 0x1c86ee },
{ "DodgerBlue3", 0x1874cd },
{ "DodgerBlue4", 0x104e8b },
{ "FloralWhite", 0xfffaf0 },
{ "ForestGreen", 0x228b22 },
{ "GhostWhite", 0xf8f8ff },
{ "GreenYellow", 0xadff2f },
{ "HotPink", 0xff69b4 },
{ "HotPink1", 0xff6eb4 },
{ "HotPink2", 0xee6aa7 },
{ "HotPink3", 0xcd6090 },
{ "HotPink4", 0x8b3a62 },
{ "IndianRed", 0xcd5c5c },
{ "IndianRed1", 0xff6a6a },
{ "IndianRed2", 0xee6363 },
{ "IndianRed3", 0xcd5555 },
{ "IndianRed4", 0x8b3a3a },
{ "LavenderBlush", 0xfff0f5 },
{ "LavenderBlush1", 0xfff0f5 },
{ "LavenderBlush2", 0xeee0e5 },
{ "LavenderBlush3", 0xcdc1c5 },
{ "LavenderBlush4", 0x8b8386 },
{ "LawnGreen", 0x7cfc00 },
{ "LemonChiffon", 0xfffacd },
{ "LemonChiffon1", 0xfffacd },
{ "LemonChiffon2", 0xeee9bf },
{ "LemonChiffon3", 0xcdc9a5 },
{ "LemonChiffon4", 0x8b8970 },
{ "LightBlue", 0xadd8e6 },
{ "LightBlue1", 0xbfefff },
{ "LightBlue2", 0xb2dfee },
{ "LightBlue3", 0x9ac0cd },
{ "LightBlue4", 0x68838b },
{ "LightCoral", 0xf08080 },
{ "LightCyan", 0xe0ffff },
{ "LightCyan1", 0xe0ffff },
{ "LightCyan2", 0xd1eeee },
{ "LightCyan3", 0xb4cdcd },
{ "LightCyan4", 0x7a8b8b },
{ "LightGoldenrod", 0xeedd82 },
{ "LightGoldenrod1", 0xffec8b },
{ "LightGoldenrod2", 0xeedc82 },
{ "LightGoldenrod3", 0xcdbe70 },
{ "LightGoldenrod4", 0x8b814c },
{ "LightGoldenrodYellow", 0xfafad2 },
{ "LightGray", 0xd3d3d3 },
{ "LightGreen", 0x90ee90 },
{ "LightGrey", 0xd3d3d3 },
{ "LightPink", 0xffb6c1 },
{ "LightPink1", 0xffaeb9 },
{ "LightPink2", 0xeea2ad },
{ "LightPink3", 0xcd8c95 },
{ "LightPink4", 0x8b5f65 },
{ "LightSalmon", 0xffa07a },
{ "LightSalmon1", 0xffa07a },
{ "LightSalmon2", 0xee9572 },
{ "LightSalmon3", 0xcd8162 },
{ "LightSalmon4", 0x8b5742 },
{ "LightSeaGreen", 0x20b2aa },
{ "LightSkyBlue", 0x87cefa },
{ "LightSkyBlue1", 0xb0e2ff },
{ "LightSkyBlue2", 0xa4d3ee },
{ "LightSkyBlue3", 0x8db6cd },
{ "LightSkyBlue4", 0x607b8b },
{ "LightSlateBlue", 0x8470ff },
{ "LightSlateGray", 0x778899 },
{ "LightSlateGrey", 0x778899 },
{ "LightSteelBlue", 0xb0c4de },
{ "LightSteelBlue1", 0xcae1ff },
{ "LightSteelBlue2", 0xbcd2ee },
{ "LightSteelBlue3", 0xa2b5cd },
{ "LightSteelBlue4", 0x6e7b8b },
{ "LightYellow", 0xffffe0 },
{ "LightYellow1", 0xffffe0 },
{ "LightYellow2", 0xeeeed1 },
{ "LightYellow3", 0xcdcdb4 },
{ "LightYellow4", 0x8b8b7a },
{ "LimeGreen", 0x32cd32 },
{ "MediumAquamarine", 0x66cdaa },
{ "MediumBlue", 0x0000cd },
{ "MediumOrchid", 0xba55d3 },
{ "MediumOrchid1", 0xe066ff },
{ "MediumOrchid2", 0xd15fee },
{ "MediumOrchid3", 0xb452cd },
{ "MediumOrchid4", 0x7a378b },
{ "MediumPurple", 0x9370db },
{ "MediumPurple1", 0xab82ff },
{ "MediumPurple2", 0x9f79ee },
{ "MediumPurple3", 0x8968cd },
{ "MediumPurple4", 0x5d478b },
{ "MediumSeaGreen", 0x3cb371 },
{ "MediumSlateBlue", 0x7b68ee },
{ "MediumSpringGreen", 0x00fa9a },
{ "MediumTurquoise", 0x48d1cc },
{ "MediumVioletRed", 0xc71585 },
{ "MidnightBlue", 0x191970 },
{ "MintCream", 0xf5fffa },
{ "MistyRose", 0xffe4e1 },
{ "MistyRose1", 0xffe4e1 },
{ "MistyRose2", 0xeed5d2 },
{ "MistyRose3", 0xcdb7b5 },
{ "MistyRose4", 0x8b7d7b },
{ "NavajoWhite", 0xffdead },
{ "NavajoWhite1", 0xffdead },
{ "NavajoWhite2", 0xeecfa1 },
{ "NavajoWhite3", 0xcdb38b },
{ "NavajoWhite4", 0x8b795e },
{ "NavyBlue", 0x000080 },
{ "OldLace", 0xfdf5e6 },
{ "OliveDrab", 0x6b8e23 },
{ "OliveDrab1", 0xc0ff3e },
{ "OliveDrab2", 0xb3ee3a },
{ "OliveDrab3", 0x9acd32 },
{ "OliveDrab4", 0x698b22 },
{ "OrangeRed", 0xff4500 },
{ "OrangeRed1", 0xff4500 },
{ "OrangeRed2", 0xee4000 },
{ "OrangeRed3", 0xcd3700 },
{ "OrangeRed4", 0x8b2500 },
{ "PaleGoldenrod", 0xeee8aa },
{ "PaleGreen", 0x98fb98 },
{ "PaleGreen1", 0x9aff9a },
{ "PaleGreen2", 0x90ee90 },
{ "PaleGreen3", 0x7ccd7c },
{ "PaleGreen4", 0x548b54 },
{ "PaleTurquoise", 0xafeeee },
{ "PaleTurquoise1", 0xbbffff },
{ "PaleTurquoise2", 0xaeeeee },
{ "PaleTurquoise3", 0x96cdcd },
{ "PaleTurquoise4", 0x668b8b },
{ "PaleVioletRed", 0xdb7093 },
{ "PaleVioletRed1", 0xff82ab },
{ "PaleVioletRed2", 0xee799f },
{ "PaleVioletRed3", 0xcd6889 },
{ "PaleVioletRed4", 0x8b475d },
{ "PapayaWhip", 0xffefd5 },
{ "PeachPuff", 0xffdab9 },
{ "PeachPuff1", 0xffdab9 },
{ "PeachPuff2", 0xeecbad },
{ "PeachPuff3", 0xcdaf95 },
{ "PeachPuff4", 0x8b7765 },
{ "PowderBlue", 0xb0e0e6 },
{ "RebeccaPurple", 0x663399 },
{ "RosyBrown", 0xbc8f8f },
{ "RosyBrown1", 0xffc1c1 },
{ "RosyBrown2", 0xeeb4b4 },
{ "RosyBrown3", 0xcd9b9b },
{ "RosyBrown4", 0x8b6969 },
{ "RoyalBlue", 0x4169e1 },
{ "RoyalBlue1", 0x4876ff },
{ "RoyalBlue2", 0x436eee },
{ "RoyalBlue3", 0x3a5fcd },
{ "RoyalBlue4", 0x27408b },
{ "SaddleBrown", 0x8b4513 },
{ "SandyBrown", 0xf4a460 },
{ "SeaGreen", 0x2e8b57 },
{ "SeaGreen1", 0x54ff9f },
{ "SeaGreen2", 0x4eee94 },
{ "SeaGreen3", 0x43cd80 },
{ "SeaGreen4", 0x2e8b57 },
{ "SkyBlue", 0x87ceeb },
{ "SkyBlue1", 0x87ceff },
{ "SkyBlue2", 0x7ec0ee },
{ "SkyBlue3", 0x6ca6cd },
{ "SkyBlue4", 0x4a708b },
{ "SlateBlue", 0x6a5acd },
{ "SlateBlue1", 0x836fff },
{ "SlateBlue2", 0x7a67ee },
{ "SlateBlue3", 0x6959cd },
{ "SlateBlue4", 0x473c8b },
{ "SlateGray", 0x708090 },
{ "SlateGray1", 0xc6e2ff },
{ "SlateGray2", 0xb9d3ee },
{ "SlateGray3", 0x9fb6cd },
{ "SlateGray4", 0x6c7b8b },
{ "SlateGrey", 0x708090 },
{ "SpringGreen", 0x00ff7f },
{ "SpringGreen1", 0x00ff7f },
{ "SpringGreen2", 0x00ee76 },
{ "SpringGreen3", 0x00cd66 },
{ "SpringGreen4", 0x008b45 },
{ "SteelBlue", 0x4682b4 },
{ "SteelBlue1", 0x63b8ff },
{ "SteelBlue2", 0x5cacee },
{ "SteelBlue3", 0x4f94cd },
{ "SteelBlue4", 0x36648b },
{ "VioletRed", 0xd02090 },
{ "VioletRed1", 0xff3e96 },
{ "VioletRed2", 0xee3a8c },
{ "VioletRed3", 0xcd3278 },
{ "VioletRed4", 0x8b2252 },
{ "WebGray", 0x808080 },
{ "WebGreen", 0x008000 },
{ "WebGrey", 0x808080 },
{ "WebMaroon", 0x800000 },
{ "WebPurple", 0x800080 },
{ "WhiteSmoke", 0xf5f5f5 },
{ "X11Gray", 0xbebebe },
{ "X11Green", 0x00ff00 },
{ "X11Grey", 0xbebebe },
{ "X11Maroon", 0xb03060 },
{ "X11Purple", 0xa020f0 },
{ "YellowGreen", 0x9acd32 },
{ "alice blue", 0xf0f8ff },
{ "antique white", 0xfaebd7 },
{ "aqua", 0x00ffff },
{ "aquamarine", 0x7fffd4 },
{ "aquamarine1", 0x7fffd4 },
{ "aquamarine2", 0x76eec6 },
{ "aquamarine3", 0x66cdaa },
{ "aquamarine4", 0x458b74 },
{ "azure", 0xf0ffff },
{ "azure1", 0xf0ffff },
{ "azure2", 0xe0eeee },
{ "azure3", 0xc1cdcd },
{ "azure4", 0x838b8b },
{ "beige", 0xf5f5dc },
{ "bisque", 0xffe4c4 },
{ "bisque1", 0xffe4c4 },
{ "bisque2", 0xeed5b7 },
{ "bisque3", 0xcdb79e },
{ "bisque4", 0x8b7d6b },
{ "black", 0x000000 },
{ "blanched almond", 0xffebcd },
{ "blue violet", 0x8a2be2 },
{ "blue", 0x0000ff },
{ "blue1", 0x0000ff },
{ "blue2", 0x0000ee },
{ "blue3", 0x0000cd },
{ "blue4", 0x00008b },
{ "brown", 0xa52a2a },
{ "brown1", 0xff4040 },
{ "brown2", 0xee3b3b },
{ "brown3", 0xcd3333 },
{ "brown4", 0x8b2323 },
{ "burlywood", 0xdeb887 },
{ "burlywood1", 0xffd39b },
{ "burlywood2", 0xeec591 },
{ "burlywood3", 0xcdaa7d },
{ "burlywood4", 0x8b7355 },
{ "cadet blue", 0x5f9ea0 },
{ "chartreuse", 0x7fff00 },
{ "chartreuse1", 0x7fff00 },
{ "chartreuse2", 0x76ee00 },
{ "chartreuse3", 0x66cd00 },
{ "chartreuse4", 0x458b00 },
{ "chocolate", 0xd2691e },
{ "chocolate1", 0xff7f24 },
{ "chocolate2", 0xee7621 },
{ "chocolate3", 0xcd661d },
{ "chocolate4", 0x8b4513 },
{ "coral", 0xff7f50 },
{ "coral1", 0xff7256 },
{ "coral2", 0xee6a50 },
{ "coral3", 0xcd5b45 },
{ "coral4", 0x8b3e2f },
{ "cornflower blue", 0x6495ed },
{ "cornsilk", 0xfff8dc },
{ "cornsilk1", 0xfff8dc },
{ "cornsilk2", 0xeee8cd },
{ "cornsilk3", 0xcdc8b1 },
{ "cornsilk4", 0x8b8878 },
{ "crimson", 0xdc143c },
{ "cyan", 0x00ffff },
{ "cyan1", 0x00ffff },
{ "cyan2", 0x00eeee },
{ "cyan3", 0x00cdcd },
{ "cyan4", 0x008b8b },
{ "dark blue", 0x00008b },
{ "dark cyan", 0x008b8b },
{ "dark goldenrod", 0xb8860b },
{ "dark gray", 0xa9a9a9 },
{ "dark green", 0x006400 },
{ "dark grey", 0xa9a9a9 },
{ "dark khaki", 0xbdb76b },
{ "dark magenta", 0x8b008b },
{ "dark olive green", 0x556b2f },
{ "dark orange", 0xff8c00 },
{ "dark orchid", 0x9932cc },
{ "dark red", 0x8b0000 },
{ "dark salmon", 0xe9967a },
{ "dark sea green", 0x8fbc8f },
{ "dark slate blue", 0x483d8b },
{ "dark slate gray", 0x2f4f4f },
{ "dark slate grey", 0x2f4f4f },
{ "dark turquoise", 0x00ced1 },
{ "dark violet", 0x9400d3 },
{ "deep pink", 0xff1493 },
{ "deep sky blue", 0x00bfff },
{ "dim gray", 0x696969 },
{ "dim grey", 0x696969 },
{ "dodger blue", 0x1e90ff },
{ "firebrick", 0xb22222 },
{ "firebrick1", 0xff3030 },
{ "firebrick2", 0xee2c2c },
{ "firebrick3", 0xcd2626 },
{ "firebrick4", 0x8b1a1a },
{ "floral white", 0xfffaf0 },
{ "forest green", 0x228b22 },
{ "fuchsia", 0xff00ff },
{ "gainsboro", 0xdcdcdc },
{ "ghost white", 0xf8f8ff },
{ "gold", 0xffd700 },
{ "gold1", 0xffd700 },
{ "gold2", 0xeec900 },
{ "gold3", 0xcdad00 },
{ "gold4", 0x8b7500 },
{ "goldenrod", 0xdaa520 },
{ "goldenrod1", 0xffc125 },
{ "goldenrod2", 0xeeb422 },
{ "goldenrod3", 0xcd9b1d },
{ "goldenrod4", 0x8b6914 },
{ "green yellow", 0xadff2f },
{ "green", 0x00ff00 },
{ "green1", 0x00ff00 },
{ "green2", 0x00ee00 },
{ "green3", 0x00cd00 },
{ "green4", 0x008b00 },
{ "honeydew", 0xf0fff0 },
{ "honeydew1", 0xf0fff0 },
{ "honeydew2", 0xe0eee0 },
{ "honeydew3", 0xc1cdc1 },
{ "honeydew4", 0x838b83 },
{ "hot pink", 0xff69b4 },
{ "indian red", 0xcd5c5c },
{ "indigo", 0x4b0082 },
{ "ivory", 0xfffff0 },
{ "ivory1", 0xfffff0 },
{ "ivory2", 0xeeeee0 },
{ "ivory3", 0xcdcdc1 },
{ "ivory4", 0x8b8b83 },
{ "khaki", 0xf0e68c },
{ "khaki1", 0xfff68f },
{ "khaki2", 0xeee685 },
{ "khaki3", 0xcdc673 },
{ "khaki4", 0x8b864e },
{ "lavender blush", 0xfff0f5 },
{ "lavender", 0xe6e6fa },
{ "lawn green", 0x7cfc00 },
{ "lemon chiffon", 0xfffacd },
{ "light blue", 0xadd8e6 },
{ "light coral", 0xf08080 },
{ "light cyan", 0xe0ffff },
{ "light goldenrod yellow", 0xfafad2 },
{ "light goldenrod", 0xeedd82 },
{ "light gray", 0xd3d3d3 },
{ "light green", 0x90ee90 },
{ "light grey", 0xd3d3d3 },
{ "light pink", 0xffb6c1 },
{ "light salmon", 0xffa07a },
{ "light sea green", 0x20b2aa },
{ "light sky blue", 0x87cefa },
{ "light slate blue", 0x8470ff },
{ "light slate gray", 0x778899 },
{ "light slate grey", 0x778899 },
{ "light steel blue", 0xb0c4de },
{ "light yellow", 0xffffe0 },
{ "lime green", 0x32cd32 },
{ "lime", 0x00ff00 },
{ "linen", 0xfaf0e6 },
{ "magenta", 0xff00ff },
{ "magenta1", 0xff00ff },
{ "magenta2", 0xee00ee },
{ "magenta3", 0xcd00cd },
{ "magenta4", 0x8b008b },
{ "maroon", 0xb03060 },
{ "maroon1", 0xff34b3 },
{ "maroon2", 0xee30a7 },
{ "maroon3", 0xcd2990 },
{ "maroon4", 0x8b1c62 },
{ "medium aquamarine", 0x66cdaa },
{ "medium blue", 0x0000cd },
{ "medium orchid", 0xba55d3 },
{ "medium purple", 0x9370db },
{ "medium sea green", 0x3cb371 },
{ "medium slate blue", 0x7b68ee },
{ "medium spring green", 0x00fa9a },
{ "medium turquoise", 0x48d1cc },
{ "medium violet red", 0xc71585 },
{ "midnight blue", 0x191970 },
{ "mint cream", 0xf5fffa },
{ "misty rose", 0xffe4e1 },
{ "moccasin", 0xffe4b5 },
{ "navajo white", 0xffdead },
{ "navy blue", 0x000080 },
{ "navy", 0x000080 },
{ "old lace", 0xfdf5e6 },
{ "olive drab", 0x6b8e23 },
{ "olive", 0x808000 },
{ "orange red", 0xff4500 },
{ "orange", 0xffa500 },
{ "orange1", 0xffa500 },
{ "orange2", 0xee9a00 },
{ "orange3", 0xcd8500 },
{ "orange4", 0x8b5a00 },
{ "orchid", 0xda70d6 },
{ "orchid1", 0xff83fa },
{ "orchid2", 0xee7ae9 },
{ "orchid3", 0xcd69c9 },
{ "orchid4", 0x8b4789 },
{ "pale goldenrod", 0xeee8aa },
{ "pale green", 0x98fb98 },
{ "pale turquoise", 0xafeeee },
{ "pale violet red", 0xdb7093 },
{ "papaya whip", 0xffefd5 },
{ "peach puff", 0xffdab9 },
{ "peru", 0xcd853f },
{ "pink", 0xffc0cb },
{ "pink1", 0xffb5c5 },
{ "pink2", 0xeea9b8 },
{ "pink3", 0xcd919e },
{ "pink4", 0x8b636c },
{ "plum", 0xdda0dd },
{ "plum1", 0xffbbff },
{ "plum2", 0xeeaeee },
{ "plum3", 0xcd96cd },
{ "plum4", 0x8b668b },
{ "powder blue", 0xb0e0e6 },
{ "purple", 0xa020f0 },
{ "purple1", 0x9b30ff },
{ "purple2", 0x912cee },
{ "purple3", 0x7d26cd },
{ "purple4", 0x551a8b },
{ "rebecca purple", 0x663399 },
{ "red", 0xff0000 },
{ "red1", 0xff0000 },
{ "red2", 0xee0000 },
{ "red3", 0xcd0000 },
{ "red4", 0x8b0000 },
{ "rosy brown", 0xbc8f8f },
{ "royal blue", 0x4169e1 },
{ "saddle brown", 0x8b4513 },
{ "salmon", 0xfa8072 },
{ "salmon1", 0xff8c69 },
{ "salmon2", 0xee8262 },
{ "salmon3", 0xcd7054 },
{ "salmon4", 0x8b4c39 },
{ "sandy brown", 0xf4a460 },
{ "sea green", 0x2e8b57 },
{ "seashell", 0xfff5ee },
{ "seashell1", 0xfff5ee },
{ "seashell2", 0xeee5de },
{ "seashell3", 0xcdc5bf },
{ "seashell4", 0x8b8682 },
{ "sienna", 0xa0522d },
{ "sienna1", 0xff8247 },
{ "sienna2", 0xee7942 },
{ "sienna3", 0xcd6839 },
{ "sienna4", 0x8b4726 },
{ "silver", 0xc0c0c0 },
{ "sky blue", 0x87ceeb },
{ "slate blue", 0x6a5acd },
{ "slate gray", 0x708090 },
{ "slate grey", 0x708090 },
{ "snow", 0xfffafa },
{ "snow1", 0xfffafa },
{ "snow2", 0xeee9e9 },
{ "snow3", 0xcdc9c9 },
{ "snow4", 0x8b8989 },
{ "spring green", 0x00ff7f },
{ "steel blue", 0x4682b4 },
{ "tan", 0xd2b48c },
{ "tan1", 0xffa54f },
{ "tan2", 0xee9a49 },
{ "tan3", 0xcd853f },
{ "tan4", 0x8b5a2b },
{ "teal", 0x008080 },
{ "thistle", 0xd8bfd8 },
{ "thistle1", 0xffe1ff },
{ "thistle2", 0xeed2ee },
{ "thistle3", 0xcdb5cd },
{ "thistle4", 0x8b7b8b },
{ "tomato", 0xff6347 },
{ "tomato1", 0xff6347 },
{ "tomato2", 0xee5c42 },
{ "tomato3", 0xcd4f39 },
{ "tomato4", 0x8b3626 },
{ "turquoise", 0x40e0d0 },
{ "turquoise1", 0x00f5ff },
{ "turquoise2", 0x00e5ee },
{ "turquoise3", 0x00c5cd },
{ "turquoise4", 0x00868b },
{ "violet red", 0xd02090 },
{ "violet", 0xee82ee },
{ "web gray", 0x808080 },
{ "web green", 0x008000 },
{ "web grey", 0x808080 },
{ "web maroon", 0x800000 },
{ "web purple", 0x800080 },
{ "wheat", 0xf5deb3 },
{ "wheat1", 0xffe7ba },
{ "wheat2", 0xeed8ae },
{ "wheat3", 0xcdba96 },
{ "wheat4", 0x8b7e66 },
{ "white smoke", 0xf5f5f5 },
{ "white", 0xffffff },
{ "x11 gray", 0xbebebe },
{ "x11 green", 0x00ff00 },
{ "x11 grey", 0xbebebe },
{ "x11 maroon", 0xb03060 },
{ "x11 purple", 0xa020f0 },
{ "yellow green", 0x9acd32 },
{ "yellow", 0xffff00 },
{ "yellow1", 0xffff00 },
{ "yellow2", 0xeeee00 },
{ "yellow3", 0xcdcd00 },
{ "yellow4", 0x8b8b00 }
};
u_int i;
int c;
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
if (!isdigit((u_char)name[4]))
return (0xbebebe|COLOUR_FLAG_RGB);
c = round(2.55 * atoi(name + 4));
if (c < 0 || c > 255)
return (-1);
return (colour_join_rgb(c, c, c));
}
for (i = 0; i < nitems(colours); i++) {
if (strcasecmp(colours[i].name, name) == 0)
return (colours[i].c|COLOUR_FLAG_RGB);
}
return (-1);
}

View File

@@ -27,35 +27,10 @@
#include <termios.h> #include <termios.h>
#include <wchar.h> #include <wchar.h>
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/bufferevent_compat.h>
#else
#include <event.h>
#endif
#ifdef HAVE_MALLOC_TRIM
#include <malloc.h>
#endif
#ifdef HAVE_UTF8PROC
#include <utf8proc.h>
#endif
#ifndef __GNUC__ #ifndef __GNUC__
#define __attribute__(a) #define __attribute__(a)
#endif #endif
#ifdef BROKEN___DEAD
#undef __dead
#endif
#ifndef __unused #ifndef __unused
#define __unused __attribute__ ((__unused__)) #define __unused __attribute__ ((__unused__))
#endif #endif
@@ -65,9 +40,6 @@
#ifndef __packed #ifndef __packed
#define __packed __attribute__ ((__packed__)) #define __packed __attribute__ ((__packed__))
#endif #endif
#ifndef __weak
#define __weak __attribute__ ((__weak__))
#endif
#ifndef ECHOPRT #ifndef ECHOPRT
#define ECHOPRT 0 #define ECHOPRT 0
@@ -118,18 +90,10 @@ void warnx(const char *, ...);
#define _PATH_DEFPATH "/usr/bin:/bin" #define _PATH_DEFPATH "/usr/bin:/bin"
#endif #endif
#ifndef _PATH_VI
#define _PATH_VI "/usr/bin/vi"
#endif
#ifndef __OpenBSD__ #ifndef __OpenBSD__
#define pledge(s, p) (0) #define pledge(s, p) (0)
#endif #endif
#ifndef IMAXBEL
#define IMAXBEL 0
#endif
#ifdef HAVE_STDINT_H #ifdef HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
#else #else
@@ -265,13 +229,6 @@ void warnx(const char *, ...);
#define HOST_NAME_MAX 255 #define HOST_NAME_MAX 255
#endif #endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef HAVE_FLOCK #ifndef HAVE_FLOCK
#define LOCK_SH 0 #define LOCK_SH 0
#define LOCK_EX 0 #define LOCK_EX 0
@@ -349,11 +306,6 @@ const char *getprogname(void);
void setproctitle(const char *, ...); void setproctitle(const char *, ...);
#endif #endif
#ifndef HAVE_CLOCK_GETTIME
/* clock_gettime.c */
int clock_gettime(int, struct timespec *);
#endif
#ifndef HAVE_B64_NTOP #ifndef HAVE_B64_NTOP
/* base64.c */ /* base64.c */
#undef b64_ntop #undef b64_ntop
@@ -385,11 +337,6 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *); char *fgetln(FILE *, size_t *);
#endif #endif
#ifndef HAVE_GETLINE
/* getline.c */
ssize_t getline(char **, size_t *, FILE *);
#endif
#ifndef HAVE_SETENV #ifndef HAVE_SETENV
/* setenv.c */ /* setenv.c */
int setenv(const char *, const char *, int); int setenv(const char *, const char *, int);
@@ -423,11 +370,6 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t); int utf8proc_wctomb(char *, wchar_t);
#endif #endif
#ifdef NEED_FUZZING
/* tmux.c */
#define main __weak main
#endif
/* getopt.c */ /* getopt.c */
extern int BSDopterr; extern int BSDopterr;
extern int BSDoptind; extern int BSDoptind;

View File

@@ -1,37 +0,0 @@
/*
* Copyright (c) 2021 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/time.h>
#include "compat.h"
#ifndef TIMEVAL_TO_TIMESPEC
#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
(ts)->tv_sec = (tv)->tv_sec; \
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
} while (0)
#endif
int
clock_gettime(int clock, struct timespec *ts)
{
struct timeval tv;
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, ts);
return 0;
}

View File

@@ -44,9 +44,6 @@
# include <ndir.h> # include <ndir.h>
# endif # endif
#endif #endif
#if defined(HAVE_LIBPROC_H)
# include <libproc.h>
#endif
#include "compat.h" #include "compat.h"
@@ -58,15 +55,39 @@
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
#endif /* lint */ #endif /* lint */
#ifndef HAVE_FCNTL_CLOSEM
/* /*
* Close all file descriptors greater than or equal to lowfd. * Close all file descriptors greater than or equal to lowfd.
*/ */
static void #ifdef HAVE_FCNTL_CLOSEM
closefrom_fallback(int lowfd) void
closefrom(int lowfd)
{ {
long fd, maxfd; (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 * Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor * resource limits since it is possible to open a file descriptor
@@ -78,78 +99,11 @@ closefrom_fallback(int lowfd)
maxfd = getdtablesize(); maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */ #endif /* HAVE_SYSCONF */
if (maxfd < 0) if (maxfd < 0)
maxfd = OPEN_MAX; maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; fd++) for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd); (void) close((int) fd);
}
#endif /* HAVE_FCNTL_CLOSEM */
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO)
void
closefrom(int lowfd)
{
int i, r, sz;
pid_t pid = getpid();
struct proc_fdinfo *fdinfo_buf = NULL;
sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (sz == 0)
return; /* no fds, really? */
else if (sz == -1)
goto fallback;
if ((fdinfo_buf = malloc(sz)) == NULL)
goto fallback;
r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz);
if (r < 0 || r > sz)
goto fallback;
for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) {
if (fdinfo_buf[i].proc_fd >= lowfd)
close(fdinfo_buf[i].proc_fd);
}
free(fdinfo_buf);
return;
fallback:
free(fdinfo_buf);
closefrom_fallback(lowfd);
return;
}
#elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
void
closefrom(int lowfd)
{
long fd;
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);
return;
} }
/* /proc/$$/fd strategy failed, fall back to brute force closure */
closefrom_fallback(lowfd);
}
#else
void
closefrom(int lowfd)
{
closefrom_fallback(lowfd);
} }
#endif /* !HAVE_FCNTL_CLOSEM */ #endif /* !HAVE_FCNTL_CLOSEM */
#endif /* HAVE_CLOSEFROM */ #endif /* HAVE_CLOSEFROM */

View File

@@ -1,82 +0,0 @@
/*
* 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 <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();
if (ioctl(slave, TIOCSCTTY, NULL) == -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);
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) 2020 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 <unistd.h>
#include "compat.h"
#ifdef HAVE_SYSCONF
int
getdtablesize(void)
{
return (sysconf(_SC_OPEN_MAX));
}
#endif

View File

@@ -1,93 +0,0 @@
/* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */
/* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "tmux.h"
static ssize_t
getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
{
char *ptr, *eptr;
if (*buf == NULL || *bufsiz == 0) {
if ((*buf = malloc(BUFSIZ)) == NULL)
return -1;
*bufsiz = BUFSIZ;
}
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
int c = fgetc(fp);
if (c == -1) {
if (feof(fp)) {
ssize_t diff = (ssize_t)(ptr - *buf);
if (diff != 0) {
*ptr = '\0';
return diff;
}
}
return -1;
}
*ptr++ = c;
if (c == delimiter) {
*ptr = '\0';
return ptr - *buf;
}
if (ptr + 2 >= eptr) {
char *nbuf;
size_t nbufsiz = *bufsiz * 2;
ssize_t d = ptr - *buf;
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
return -1;
*buf = nbuf;
*bufsiz = nbufsiz;
eptr = nbuf + nbufsiz;
ptr = nbuf + d;
}
}
}
ssize_t
getline(char **buf, size_t *bufsiz, FILE *fp)
{
return getdelim(buf, bufsiz, '\n', fp);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg-buffer.c,v 1.12 2019/01/20 02:50:03 bcook Exp $ */ /* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -70,7 +70,7 @@ ibuf_dynamic(size_t len, size_t max)
static int static int
ibuf_realloc(struct ibuf *buf, size_t len) ibuf_realloc(struct ibuf *buf, size_t len)
{ {
unsigned char *b; u_char *b;
/* on static buffers max is eq size and so the following fails */ /* on static buffers max is eq size and so the following fails */
if (buf->wpos + len > buf->max) { if (buf->wpos + len > buf->max) {

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg.h,v 1.5 2019/01/20 02:50:03 bcook Exp $ */ /* $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 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -21,15 +21,13 @@
#ifndef _IMSG_H_ #ifndef _IMSG_H_
#define _IMSG_H_ #define _IMSG_H_
#include <stdint.h>
#define IBUF_READ_SIZE 65535 #define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384 #define MAX_IMSGSIZE 16384
struct ibuf { struct ibuf {
TAILQ_ENTRY(ibuf) entry; TAILQ_ENTRY(ibuf) entry;
unsigned char *buf; u_char *buf;
size_t size; size_t size;
size_t max; size_t max;
size_t wpos; size_t wpos;
@@ -44,8 +42,8 @@ struct msgbuf {
}; };
struct ibuf_read { struct ibuf_read {
unsigned char buf[IBUF_READ_SIZE]; u_char buf[IBUF_READ_SIZE];
unsigned char *rptr; u_char *rptr;
size_t wpos; size_t wpos;
}; };

View File

@@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT([tmux], 3.2) AC_INIT([tmux], 3.1c)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@@ -21,26 +21,6 @@ SAVED_CFLAGS="$CFLAGS"
SAVED_CPPFLAGS="$CPPFLAGS" SAVED_CPPFLAGS="$CPPFLAGS"
SAVED_LDFLAGS="$LDFLAGS" SAVED_LDFLAGS="$LDFLAGS"
# Is this oss-fuzz build?
AC_ARG_ENABLE(
fuzzing,
AC_HELP_STRING(--enable-fuzzing, build fuzzers)
)
AC_ARG_VAR(
FUZZING_LIBS,
AC_HELP_STRING(libraries to link fuzzing targets with)
)
# Set up convenient fuzzing defaults before initializing compiler.
if test "x$enable_fuzzing" = xyes; then
AC_DEFINE(NEED_FUZZING)
test "x$CC" == x && CC=clang
test "x$FUZZING_LIBS" == x && \
FUZZING_LIBS="-fsanitize=fuzzer"
test "x$SAVED_CFLAGS" == x && \
AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address"
fi
# Set up the compiler in two different ways and say yes we may want to install. # Set up the compiler in two different ways and say yes we may want to install.
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
@@ -74,11 +54,8 @@ if test "x$enable_static" = xyes; then
LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS"
fi fi
# Do we need fuzzers?
AM_CONDITIONAL(NEED_FUZZING, test "x$enable_fuzzing" = xyes)
# Is this gcc? # Is this gcc?
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes -a "x$enable_fuzzing" != xyes) AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
# Is this Sun CC? # Is this Sun CC?
AC_EGREP_CPP( AC_EGREP_CPP(
@@ -99,7 +76,6 @@ AC_CHECK_HEADERS([ \
dirent.h \ dirent.h \
fcntl.h \ fcntl.h \
inttypes.h \ inttypes.h \
libproc.h \
libutil.h \ libutil.h \
ndir.h \ ndir.h \
paths.h \ paths.h \
@@ -111,12 +87,6 @@ AC_CHECK_HEADERS([ \
util.h \ util.h \
]) ])
# Look for sys_signame.
AC_SEARCH_LIBS(sys_signame, , AC_DEFINE(HAVE_SYS_SIGNAME))
# Look for fmod.
AC_CHECK_LIB(m, fmod)
# Look for library needed for flock. # Look for library needed for flock.
AC_SEARCH_LIBS(flock, bsd) AC_SEARCH_LIBS(flock, bsd)
@@ -125,24 +95,22 @@ AC_CHECK_FUNCS([ \
dirfd \ dirfd \
flock \ flock \
prctl \ prctl \
proc_pidinfo \ sysconf \
sysconf
]) ])
# Check for functions with a compatibility implementation. # Check for functions with a compatibility implementation.
AC_REPLACE_FUNCS([ \ AC_REPLACE_FUNCS([ \
asprintf \ asprintf \
cfmakeraw \ cfmakeraw \
clock_gettime \
closefrom \ closefrom \
explicit_bzero \ explicit_bzero \
fgetln \ fgetln \
freezero \ freezero \
getdtablecount \ getdtablecount \
getdtablesize \
getline \
getprogname \ getprogname \
memmem \ memmem \
recallocarray \
reallocarray \
setenv \ setenv \
setproctitle \ setproctitle \
strcasestr \ strcasestr \
@@ -154,26 +122,6 @@ AC_REPLACE_FUNCS([ \
]) ])
AC_FUNC_STRNLEN AC_FUNC_STRNLEN
# Clang sanitizers wrap reallocarray even if it isn't available on the target
# system. When compiled it always returns NULL and crashes the program. To
# detect this we need a more complicated test.
AC_MSG_CHECKING([for working reallocarray])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (reallocarray(NULL, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])]
)
AC_MSG_CHECKING([for working recallocarray])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (recallocarray(NULL, 1, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])]
)
# Look for clock_gettime. Must come before event_init. # Look for clock_gettime. Must come before event_init.
AC_SEARCH_LIBS(clock_gettime, rt) AC_SEARCH_LIBS(clock_gettime, rt)
@@ -183,112 +131,88 @@ AC_SEARCH_LIBS(clock_gettime, rt)
# implementations. # implementations.
AC_LIBOBJ(getopt) AC_LIBOBJ(getopt)
# Look for libevent. Try libevent_core or libevent with pkg-config first then # Look for libevent.
# look for the library.
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBEVENT_CORE, LIBEVENT,
[libevent_core >= 2], libevent,
[ [
AM_CPPFLAGS="$LIBEVENT_CORE_CFLAGS $AM_CPPFLAGS" AM_CFLAGS="$LIBEVENT_CFLAGS $AM_CFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS" CFLAGS="$AM_CFLAGS $SAVED_CFLAGS"
LIBS="$LIBEVENT_CORE_LIBS $LIBS" LIBS="$LIBEVENT_LIBS $LIBS"
found_libevent=yes found_libevent=yes
], ],
found_libevent=no
)
if test x$found_libevent = xno; then
PKG_CHECK_MODULES(
LIBEVENT,
[libevent >= 2],
[
AM_CPPFLAGS="$LIBEVENT_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBEVENT_LIBS $LIBS"
found_libevent=yes
],
found_libevent=no
)
fi
if test x$found_libevent = xno; then
AC_SEARCH_LIBS(
event_init,
[event_core event event-1.4],
found_libevent=yes,
found_libevent=no
)
fi
AC_CHECK_HEADER(
event2/event.h,
AC_DEFINE(HAVE_EVENT2_EVENT_H),
[ [
AC_CHECK_HEADER( AC_SEARCH_LIBS(
event.h, event_init,
AC_DEFINE(HAVE_EVENT_H), [event event-1.4 event2],
found_libevent=yes,
found_libevent=no found_libevent=no
) )
] ]
) )
AC_CHECK_HEADER(
event.h,
,
found_libevent=no
)
if test "x$found_libevent" = xno; then if test "x$found_libevent" = xno; then
AC_MSG_ERROR("libevent not found") AC_MSG_ERROR("libevent not found")
fi fi
# Look for ncurses or curses. Try pkg-config first then directly for the # Look for ncurses.
# library.
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBTINFO, LIBTINFO,
tinfo, tinfo,
[ found_ncurses=yes,
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBTINFO_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no found_ncurses=no
) )
if test "x$found_ncurses" = xno; then if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBNCURSES, LIBNCURSES,
ncurses, ncurses,
[ found_ncurses=yes,
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no found_ncurses=no
) )
fi fi
if test "x$found_ncurses" = xno; then if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
LIBNCURSESW, LIBNCURSES,
ncursesw, ncursesw,
[
AM_CPPFLAGS="$LIBNCURSESW_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSESW_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSESW_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no
)
fi
if test "x$found_ncurses" = xno; then
AC_SEARCH_LIBS(
setupterm,
[tinfo ncurses ncursesw],
found_ncurses=yes, found_ncurses=yes,
found_ncurses=no 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 if test "x$found_ncurses" = xyes; then
AC_CHECK_HEADER( AC_CHECK_HEADER(
ncurses.h, ncurses.h,
LIBS="$LIBS -lncurses", LIBS="$LIBS -lncurses",
found_ncurses=no found_ncurses=no)
)
fi fi
fi fi
if test "x$found_ncurses" = xyes; then if test "x$found_ncurses" = xyes; then
AC_DEFINE(HAVE_NCURSES_H) AC_DEFINE(HAVE_NCURSES_H)
else else
# No ncurses, try curses.
AC_CHECK_LIB( AC_CHECK_LIB(
curses, curses,
setupterm, setupterm,
@@ -298,8 +222,7 @@ else
AC_CHECK_HEADER( AC_CHECK_HEADER(
curses.h, curses.h,
, ,
found_curses=no found_curses=no)
)
if test "x$found_curses" = xyes; then if test "x$found_curses" = xyes; then
LIBS="$LIBS -lcurses" LIBS="$LIBS -lcurses"
AC_DEFINE(HAVE_CURSES_H) AC_DEFINE(HAVE_CURSES_H)
@@ -365,11 +288,12 @@ AC_TRY_LINK(
found_b64_ntop=yes, found_b64_ntop=yes,
found_b64_ntop=no found_b64_ntop=no
) )
AC_MSG_RESULT($found_b64_ntop)
OLD_LIBS="$LIBS"
if test "x$found_b64_ntop" = xno; then if test "x$found_b64_ntop" = xno; then
AC_MSG_RESULT(no)
AC_MSG_CHECKING(for b64_ntop with -lresolv) AC_MSG_CHECKING(for b64_ntop with -lresolv)
LIBS="$OLD_LIBS -lresolv" OLD_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_TRY_LINK( AC_TRY_LINK(
[ [
#include <sys/types.h> #include <sys/types.h>
@@ -380,27 +304,15 @@ if test "x$found_b64_ntop" = xno; then
found_b64_ntop=yes, found_b64_ntop=yes,
found_b64_ntop=no found_b64_ntop=no
) )
AC_MSG_RESULT($found_b64_ntop) if test "x$found_b64_ntop" = xno; then
fi LIBS="$OLD_LIBS"
if test "x$found_b64_ntop" = xno; then AC_MSG_RESULT(no)
AC_MSG_CHECKING(for b64_ntop with -lnetwork) fi
LIBS="$OLD_LIBS -lnetwork"
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
)
AC_MSG_RESULT($found_b64_ntop)
fi fi
if test "x$found_b64_ntop" = xyes; then if test "x$found_b64_ntop" = xyes; then
AC_DEFINE(HAVE_B64_NTOP) AC_DEFINE(HAVE_B64_NTOP)
AC_MSG_RESULT(yes)
else else
LIBS="$OLD_LIBS"
AC_LIBOBJ(base64) AC_LIBOBJ(base64)
fi fi
@@ -409,34 +321,8 @@ AC_SEARCH_LIBS(inet_ntoa, nsl)
AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(socket, socket)
AC_CHECK_LIB(xnet, socket) AC_CHECK_LIB(xnet, socket)
# Check if using glibc and have malloc_trim(3). The glibc free(3) is pretty bad # Check for CMSG_DATA. Some platforms require _XOPEN_SOURCE_EXTENDED (for
# about returning memory to the kernel unless the application tells it when to # example see xopen_networking(7) on HP-UX).
# with malloc_trim(3).
AC_MSG_CHECKING(if free doesn't work very well)
AC_LINK_IFELSE([AC_LANG_SOURCE(
[
#include <stdlib.h>
#ifdef __GLIBC__
#include <malloc.h>
int main(void) {
malloc_trim (0);
exit(0);
}
#else
no
#endif
])],
found_malloc_trim=yes,
found_malloc_trim=no
)
AC_MSG_RESULT($found_malloc_trim)
if test "x$found_malloc_trim" = xyes; then
AC_DEFINE(HAVE_MALLOC_TRIM)
fi
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
XOPEN_DEFINES= XOPEN_DEFINES=
AC_MSG_CHECKING(for CMSG_DATA) AC_MSG_CHECKING(for CMSG_DATA)
AC_EGREP_CPP( AC_EGREP_CPP(
@@ -469,25 +355,6 @@ if test "x$found_cmsg_data" = xno; then
AC_MSG_RESULT($found_cmsg_data) AC_MSG_RESULT($found_cmsg_data)
if test "x$found_cmsg_data" = xyes; then if test "x$found_cmsg_data" = xyes; then
XOPEN_DEFINES="-D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED" XOPEN_DEFINES="-D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED"
fi
fi
if test "x$found_cmsg_data" = xno; then
AC_MSG_CHECKING(if CMSG_DATA needs _XOPEN_SOURCE 600)
AC_EGREP_CPP(
yes,
[
#define _XOPEN_SOURCE 600
#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=600"
else else
AC_MSG_ERROR("CMSG_DATA not found") AC_MSG_ERROR("CMSG_DATA not found")
fi fi
@@ -676,12 +543,6 @@ case "$host_os" in
AC_MSG_RESULT(darwin) AC_MSG_RESULT(darwin)
PLATFORM=darwin PLATFORM=darwin
# #
# OS X uses __dead2 instead of __dead, like FreeBSD. But it
# defines __dead away so it needs to be removed before we can
# replace it.
#
AC_DEFINE(BROKEN___DEAD)
#
# OS X CMSG_FIRSTHDR is broken, so redefine it with a working # OS X CMSG_FIRSTHDR is broken, so redefine it with a working
# one. daemon works but has some stupid side effects, so use # one. daemon works but has some stupid side effects, so use
# our internal version which has a workaround. # our internal version which has a workaround.
@@ -736,10 +597,6 @@ case "$host_os" in
AC_MSG_RESULT(cygwin) AC_MSG_RESULT(cygwin)
PLATFORM=cygwin PLATFORM=cygwin
;; ;;
*haiku*)
AC_MSG_RESULT(haiku)
PLATFORM=haiku
;;
*) *)
AC_MSG_RESULT(unknown) AC_MSG_RESULT(unknown)
PLATFORM=unknown PLATFORM=unknown
@@ -755,7 +612,6 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd) AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos) AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user

View File

@@ -26,6 +26,40 @@
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \ #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
((c) != NULL && ((c)->flags & CLIENT_CONTROL)) ((c) != NULL && ((c)->flags & CLIENT_CONTROL))
void
control_notify_input(struct client *c, struct window_pane *wp,
const u_char *buf, size_t len)
{
struct evbuffer *message;
u_int i;
if (c->session == NULL)
return;
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
return;
/*
* Only write input if the window pane is linked to a window belonging
* to the client's session.
*/
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new();
if (message == NULL)
fatalx("out of memory");
evbuffer_add_printf(message, "%%output %%%u ", wp->id);
for (i = 0; i < len; i++) {
if (buf[i] < ' ' || buf[i] == '\\')
evbuffer_add_printf(message, "\\%03o", buf[i]);
else
evbuffer_add_printf(message, "%c", buf[i]);
}
evbuffer_add(message, "", 1);
control_write(c, "%s", EVBUFFER_DATA(message));
evbuffer_free(message);
}
}
void void
control_notify_pane_mode_changed(int pane) control_notify_pane_mode_changed(int pane)
{ {
@@ -49,7 +83,7 @@ control_notify_window_layout_changed(struct window *w)
char *cp; char *cp;
template = "%layout-change #{window_id} #{window_layout} " template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_raw_flags}"; "#{window_visible_layout} #{window_flags}";
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
@@ -171,17 +205,6 @@ control_notify_client_session_changed(struct client *cc)
} }
} }
void
control_notify_client_detached(struct client *cc)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
control_write(c, "%%client-detached %s", cc->name);
}
}
void void
control_notify_session_renamed(struct session *s) control_notify_session_renamed(struct session *s)
{ {

1067
control.c

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -87,10 +86,8 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
RB_FOREACH(envent, environ, srcenv) { RB_FOREACH(envent, environ, srcenv) {
if (envent->value == NULL) if (envent->value == NULL)
environ_clear(dstenv, envent->name); environ_clear(dstenv, envent->name);
else { else
environ_set(dstenv, envent->name, envent->flags, environ_set(dstenv, envent->name, "%s", envent->value);
"%s", envent->value);
}
} }
} }
@@ -106,21 +103,18 @@ environ_find(struct environ *env, const char *name)
/* Set an environment variable. */ /* Set an environment variable. */
void void
environ_set(struct environ *env, const char *name, int flags, const char *fmt, environ_set(struct environ *env, const char *name, const char *fmt, ...)
...)
{ {
struct environ_entry *envent; struct environ_entry *envent;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
if ((envent = environ_find(env, name)) != NULL) { if ((envent = environ_find(env, name)) != NULL) {
envent->flags = flags;
free(envent->value); free(envent->value);
xvasprintf(&envent->value, fmt, ap); xvasprintf(&envent->value, fmt, ap);
} else { } else {
envent = xmalloc(sizeof *envent); envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name); envent->name = xstrdup(name);
envent->flags = flags;
xvasprintf(&envent->value, fmt, ap); xvasprintf(&envent->value, fmt, ap);
RB_INSERT(environ, env, envent); RB_INSERT(environ, env, envent);
} }
@@ -139,7 +133,6 @@ environ_clear(struct environ *env, const char *name)
} else { } else {
envent = xmalloc(sizeof *envent); envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name); envent->name = xstrdup(name);
envent->flags = 0;
envent->value = NULL; envent->value = NULL;
RB_INSERT(environ, env, envent); RB_INSERT(environ, env, envent);
} }
@@ -147,7 +140,7 @@ environ_clear(struct environ *env, const char *name)
/* Set an environment variable from a NAME=VALUE string. */ /* Set an environment variable from a NAME=VALUE string. */
void void
environ_put(struct environ *env, const char *var, int flags) environ_put(struct environ *env, const char *var)
{ {
char *name, *value; char *name, *value;
@@ -159,7 +152,7 @@ environ_put(struct environ *env, const char *var, int flags)
name = xstrdup(var); name = xstrdup(var);
name[strcspn(name, "=")] = '\0'; name[strcspn(name, "=")] = '\0';
environ_set(env, name, flags, "%s", value); environ_set(env, name, "%s", value);
free(name); free(name);
} }
@@ -177,7 +170,7 @@ environ_unset(struct environ *env, const char *name)
free(envent); free(envent);
} }
/* Copy variables from a destination into a source environment. */ /* Copy variables from a destination into a source * environment. */
void void
environ_update(struct options *oo, struct environ *src, struct environ *dst) environ_update(struct options *oo, struct environ *src, struct environ *dst)
{ {
@@ -192,14 +185,10 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
a = options_array_first(o); a = options_array_first(o);
while (a != NULL) { while (a != NULL) {
ov = options_array_item_value(a); ov = options_array_item_value(a);
RB_FOREACH(envent, environ, src) { if ((envent = environ_find(src, ov->string)) == NULL)
if (fnmatch(ov->string, envent->name, 0) == 0)
break;
}
if (envent == NULL)
environ_clear(dst, ov->string); environ_clear(dst, ov->string);
else else
environ_set(dst, envent->name, 0, "%s", envent->value); environ_set(dst, envent->name, "%s", envent->value);
a = options_array_next(a); a = options_array_next(a);
} }
} }
@@ -212,9 +201,7 @@ environ_push(struct environ *env)
environ = xcalloc(1, sizeof *environ); environ = xcalloc(1, sizeof *environ);
RB_FOREACH(envent, environ, env) { RB_FOREACH(envent, environ, env) {
if (envent->value != NULL && if (envent->value != NULL && *envent->name != '\0')
*envent->name != '\0' &&
(~envent->flags & ENVIRON_HIDDEN))
setenv(envent->name, envent->value, 1); setenv(envent->name, envent->value, 1);
} }
} }
@@ -256,17 +243,14 @@ environ_for_session(struct session *s, int no_TERM)
if (!no_TERM) { if (!no_TERM) {
value = options_get_string(global_options, "default-terminal"); value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", 0, "%s", value); environ_set(env, "TERM", "%s", value);
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
} }
if (s != NULL) if (s != NULL)
idx = s->id; idx = s->id;
else else
idx = -1; idx = -1;
environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(), environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
idx);
return (env); return (env);
} }

464
file.c
View File

@@ -27,17 +27,10 @@
#include "tmux.h" #include "tmux.h"
/*
* IPC file handling. Both client and server use the same data structures
* (client_file and client_files) to store list of active files. Most functions
* are for use either in client or server but not both.
*/
static int file_next_stream = 3; static int file_next_stream = 3;
RB_GENERATE(client_files, client_file, entry, file_cmp); RB_GENERATE(client_files, client_file, entry, file_cmp);
/* Get path for file, either as given or from working directory. */
static char * static char *
file_get_path(struct client *c, const char *file) file_get_path(struct client *c, const char *file)
{ {
@@ -50,7 +43,6 @@ file_get_path(struct client *c, const char *file)
return (path); return (path);
} }
/* Tree comparison function. */
int int
file_cmp(struct client_file *cf1, struct client_file *cf2) file_cmp(struct client_file *cf1, struct client_file *cf2)
{ {
@@ -61,47 +53,11 @@ file_cmp(struct client_file *cf1, struct client_file *cf2)
return (0); return (0);
} }
/*
* Create a file object in the client process - the peer is the server to send
* messages to. Check callback is fired when the file is finished with so the
* process can decide if it needs to exit (if it is waiting for files to
* flush).
*/
struct client_file * struct client_file *
file_create_with_peer(struct tmuxpeer *peer, struct client_files *files, file_create(struct client *c, int stream, client_file_cb cb, void *cbdata)
int stream, client_file_cb cb, void *cbdata)
{ {
struct client_file *cf; struct client_file *cf;
cf = xcalloc(1, sizeof *cf);
cf->c = NULL;
cf->references = 1;
cf->stream = stream;
cf->buffer = evbuffer_new();
if (cf->buffer == NULL)
fatalx("out of memory");
cf->cb = cb;
cf->data = cbdata;
cf->peer = peer;
cf->tree = files;
RB_INSERT(client_files, files, cf);
return (cf);
}
/* Create a file object in the server, communicating with the given client. */
struct client_file *
file_create_with_client(struct client *c, int stream, client_file_cb cb,
void *cbdata)
{
struct client_file *cf;
if (c != NULL && (c->flags & CLIENT_ATTACHED))
c = NULL;
cf = xcalloc(1, sizeof *cf); cf = xcalloc(1, sizeof *cf);
cf->c = c; cf->c = c;
cf->references = 1; cf->references = 1;
@@ -115,8 +71,6 @@ file_create_with_client(struct client *c, int stream, client_file_cb cb,
cf->data = cbdata; cf->data = cbdata;
if (cf->c != NULL) { if (cf->c != NULL) {
cf->peer = cf->c->peer;
cf->tree = &cf->c->files;
RB_INSERT(client_files, &cf->c->files, cf); RB_INSERT(client_files, &cf->c->files, cf);
cf->c->references++; cf->c->references++;
} }
@@ -124,7 +78,6 @@ file_create_with_client(struct client *c, int stream, client_file_cb cb,
return (cf); return (cf);
} }
/* Free a file. */
void void
file_free(struct client_file *cf) file_free(struct client_file *cf)
{ {
@@ -134,15 +87,13 @@ file_free(struct client_file *cf)
evbuffer_free(cf->buffer); evbuffer_free(cf->buffer);
free(cf->path); free(cf->path);
if (cf->tree != NULL) if (cf->c != NULL) {
RB_REMOVE(client_files, cf->tree, cf); RB_REMOVE(client_files, &cf->c->files, cf);
if (cf->c != NULL)
server_client_unref(cf->c); server_client_unref(cf->c);
}
free(cf); free(cf);
} }
/* Event to fire the done callback. */
static void static void
file_fire_done_cb(__unused int fd, __unused short events, void *arg) file_fire_done_cb(__unused int fd, __unused short events, void *arg)
{ {
@@ -154,22 +105,21 @@ file_fire_done_cb(__unused int fd, __unused short events, void *arg)
file_free(cf); file_free(cf);
} }
/* Add an event to fire the done callback (used by the server). */
void void
file_fire_done(struct client_file *cf) file_fire_done(struct client_file *cf)
{ {
event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL); event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
} }
/* Fire the read callback. */
void void
file_fire_read(struct client_file *cf) file_fire_read(struct client_file *cf)
{ {
struct client *c = cf->c;
if (cf->cb != NULL) if (cf->cb != NULL)
cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data); cf->cb(c, cf->path, cf->error, 0, cf->buffer, cf->data);
} }
/* Can this file be printed to? */
int int
file_can_print(struct client *c) file_can_print(struct client *c)
{ {
@@ -180,7 +130,6 @@ file_can_print(struct client *c)
return (1); return (1);
} }
/* Print a message to a file. */
void void
file_print(struct client *c, const char *fmt, ...) file_print(struct client *c, const char *fmt, ...)
{ {
@@ -191,7 +140,6 @@ file_print(struct client *c, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
/* Print a message to a file. */
void void
file_vprint(struct client *c, const char *fmt, va_list ap) file_vprint(struct client *c, const char *fmt, va_list ap)
{ {
@@ -203,7 +151,7 @@ file_vprint(struct client *c, const char *fmt, va_list ap)
find.stream = 1; find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 1, NULL, NULL); cf = file_create(c, 1, NULL, NULL);
cf->path = xstrdup("-"); cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap); evbuffer_add_vprintf(cf->buffer, fmt, ap);
@@ -218,7 +166,6 @@ file_vprint(struct client *c, const char *fmt, va_list ap)
} }
} }
/* Print a buffer to a file. */
void void
file_print_buffer(struct client *c, void *data, size_t size) file_print_buffer(struct client *c, void *data, size_t size)
{ {
@@ -230,7 +177,7 @@ file_print_buffer(struct client *c, void *data, size_t size)
find.stream = 1; find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 1, NULL, NULL); cf = file_create(c, 1, NULL, NULL);
cf->path = xstrdup("-"); cf->path = xstrdup("-");
evbuffer_add(cf->buffer, data, size); evbuffer_add(cf->buffer, data, size);
@@ -245,7 +192,6 @@ file_print_buffer(struct client *c, void *data, size_t size)
} }
} }
/* Report an error to a file. */
void void
file_error(struct client *c, const char *fmt, ...) file_error(struct client *c, const char *fmt, ...)
{ {
@@ -260,7 +206,7 @@ file_error(struct client *c, const char *fmt, ...)
find.stream = 2; find.stream = 2;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 2, NULL, NULL); cf = file_create(c, 2, NULL, NULL);
cf->path = xstrdup("-"); cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap); evbuffer_add_vprintf(cf->buffer, fmt, ap);
@@ -277,34 +223,30 @@ file_error(struct client *c, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
/* Write data to a file. */
void void
file_write(struct client *c, const char *path, int flags, const void *bdata, file_write(struct client *c, const char *path, int flags, const void *bdata,
size_t bsize, client_file_cb cb, void *cbdata) size_t bsize, client_file_cb cb, void *cbdata)
{ {
struct client_file *cf; struct client_file *cf;
FILE *f;
struct msg_write_open *msg; struct msg_write_open *msg;
size_t msglen; size_t msglen;
int fd = -1; int fd = -1;
u_int stream = file_next_stream++;
FILE *f;
const char *mode; const char *mode;
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cf = file_create_with_client(c, stream, cb, cbdata); cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = xstrdup("-"); cf->path = xstrdup("-");
fd = STDOUT_FILENO; fd = STDOUT_FILENO;
if (c == NULL || if (c == NULL || c->flags & CLIENT_ATTACHED) {
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF; cf->error = EBADF;
goto done; goto done;
} }
goto skip; goto skip;
} }
cf = file_create_with_client(c, stream, cb, cbdata); cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = file_get_path(c, path); cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) { if (c == NULL || c->flags & CLIENT_ATTACHED) {
@@ -339,7 +281,7 @@ skip:
msg->fd = fd; msg->fd = fd;
msg->flags = flags; msg->flags = flags;
memcpy(msg + 1, cf->path, msglen - sizeof *msg); memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { if (proc_send(c->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
free(msg); free(msg);
cf->error = EINVAL; cf->error = EINVAL;
goto done; goto done;
@@ -351,34 +293,29 @@ done:
file_fire_done(cf); file_fire_done(cf);
} }
/* Read a file. */
void void
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
{ {
struct client_file *cf; struct client_file *cf;
struct msg_read_open *msg;
size_t msglen;
int fd = -1;
u_int stream = file_next_stream++;
FILE *f; FILE *f;
size_t size; struct msg_read_open *msg;
size_t msglen, size;
int fd = -1;
char buffer[BUFSIZ]; char buffer[BUFSIZ];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cf = file_create_with_client(c, stream, cb, cbdata); cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = xstrdup("-"); cf->path = xstrdup("-");
fd = STDIN_FILENO; fd = STDIN_FILENO;
if (c == NULL || if (c == NULL || c->flags & CLIENT_ATTACHED) {
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF; cf->error = EBADF;
goto done; goto done;
} }
goto skip; goto skip;
} }
cf = file_create_with_client(c, stream, cb, cbdata); cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = file_get_path(c, path); cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) { if (c == NULL || c->flags & CLIENT_ATTACHED) {
@@ -414,7 +351,7 @@ skip:
msg->stream = cf->stream; msg->stream = cf->stream;
msg->fd = fd; msg->fd = fd;
memcpy(msg + 1, cf->path, msglen - sizeof *msg); memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { if (proc_send(c->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
free(msg); free(msg);
cf->error = EINVAL; cf->error = EINVAL;
goto done; goto done;
@@ -426,21 +363,21 @@ done:
file_fire_done(cf); file_fire_done(cf);
} }
/* Push event, fired if there is more writing to be done. */
static void static void
file_push_cb(__unused int fd, __unused short events, void *arg) file_push_cb(__unused int fd, __unused short events, void *arg)
{ {
struct client_file *cf = arg; struct client_file *cf = arg;
struct client *c = cf->c;
if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD) if (~c->flags & CLIENT_DEAD)
file_push(cf); file_push(cf);
file_free(cf); file_free(cf);
} }
/* Push uwritten data to the client for a file, if it will accept it. */
void void
file_push(struct client_file *cf) file_push(struct client_file *cf)
{ {
struct client *c = cf->c;
struct msg_write_data *msg; struct msg_write_data *msg;
size_t msglen, sent, left; size_t msglen, sent, left;
struct msg_write_close close; struct msg_write_close close;
@@ -456,364 +393,21 @@ file_push(struct client_file *cf)
msg = xrealloc(msg, msglen); msg = xrealloc(msg, msglen);
msg->stream = cf->stream; msg->stream = cf->stream;
memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent); memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0) if (proc_send(c->peer, MSG_WRITE, -1, msg, msglen) != 0)
break; break;
evbuffer_drain(cf->buffer, sent); evbuffer_drain(cf->buffer, sent);
left = EVBUFFER_LENGTH(cf->buffer); left = EVBUFFER_LENGTH(cf->buffer);
log_debug("file %d sent %zu, left %zu", cf->stream, sent, left); log_debug("%s: file %d sent %zu, left %zu", c->name, cf->stream,
sent, left);
} }
if (left != 0) { if (left != 0) {
cf->references++; cf->references++;
event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL); event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL);
} else if (cf->stream > 2) { } else if (cf->stream > 2) {
close.stream = cf->stream; close.stream = cf->stream;
proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); proc_send(c->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
file_fire_done(cf); file_fire_done(cf);
} }
free(msg); free(msg);
} }
/* Check if any files have data left to write. */
int
file_write_left(struct client_files *files)
{
struct client_file *cf;
size_t left;
int waiting = 0;
RB_FOREACH(cf, client_files, files) {
if (cf->event == NULL)
continue;
left = EVBUFFER_LENGTH(cf->event->output);
if (left != 0) {
waiting++;
log_debug("file %u %zu bytes left", cf->stream, left);
}
}
return (waiting != 0);
}
/* Client file write error callback. */
static void
file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
void *arg)
{
struct client_file *cf = arg;
log_debug("write error file %d", cf->stream);
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
bufferevent_free(cf->event);
cf->event = NULL;
close(cf->fd);
cf->fd = -1;
}
/* Client file write callback. */
static void
file_write_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
log_debug("write check file %d", cf->stream);
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, cf->tree, cf);
file_free(cf);
}
}
/* Handle a file write open message (client). */
void
file_write_open(struct client_files *files, struct tmuxpeer *peer,
struct imsg *imsg, int allow_streams, int close_received,
client_file_cb cb, void *cbdata)
{
struct msg_write_open *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
const char *path;
struct msg_write_ready reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
int error = 0;
if (msglen < sizeof *msg)
fatalx("bad MSG_WRITE_OPEN size");
if (msglen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open write file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
error = EBADF;
goto reply;
}
cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, msg->flags|flags, 0644);
else if (allow_streams) {
if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (close_received)
close(msg->fd); /* can only be used once */
}
} else
errno = EBADF;
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
file_write_error_callback, cf);
bufferevent_enable(cf->event, EV_WRITE);
goto reply;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
}
/* Handle a file write data message (client). */
void
file_write_data(struct client_files *files, struct imsg *imsg)
{
struct msg_write_data *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
size_t size = msglen - sizeof *msg;
if (msglen < sizeof *msg)
fatalx("bad MSG_WRITE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("write %zu to file %d", size, cf->stream);
if (cf->event != NULL)
bufferevent_write(cf->event, msg + 1, size);
}
/* Handle a file write close message (client). */
void
file_write_close(struct client_files *files, struct imsg *imsg)
{
struct msg_write_close *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_WRITE_CLOSE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("close file %d", cf->stream);
if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
if (cf->event != NULL)
bufferevent_free(cf->event);
if (cf->fd != -1)
close(cf->fd);
RB_REMOVE(client_files, files, cf);
file_free(cf);
}
}
/* Client file read error callback. */
static void
file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
void *arg)
{
struct client_file *cf = arg;
struct msg_read_done msg;
log_debug("read error file %d", cf->stream);
msg.stream = cf->stream;
msg.error = 0;
proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, cf->tree, cf);
file_free(cf);
}
/* Client file read callback. */
static void
file_read_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
void *bdata;
size_t bsize;
struct msg_read_data *msg;
size_t msglen;
msg = xmalloc(sizeof *msg);
for (;;) {
bdata = EVBUFFER_DATA(cf->event->input);
bsize = EVBUFFER_LENGTH(cf->event->input);
if (bsize == 0)
break;
if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
log_debug("read %zu from file %d", bsize, cf->stream);
msglen = (sizeof *msg) + bsize;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, bdata, bsize);
proc_send(cf->peer, MSG_READ, -1, msg, msglen);
evbuffer_drain(cf->event->input, bsize);
}
free(msg);
}
/* Handle a file read open message (client). */
void
file_read_open(struct client_files *files, struct tmuxpeer *peer,
struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb,
void *cbdata)
{
struct msg_read_open *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
const char *path;
struct msg_read_done reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_RDONLY;
int error;
if (msglen < sizeof *msg)
fatalx("bad MSG_READ_OPEN size");
if (msglen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open read file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
error = EBADF;
goto reply;
}
cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, flags);
else if (allow_streams) {
if (msg->fd != STDIN_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (close_received)
close(msg->fd); /* can only be used once */
}
} else
errno = EBADF;
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
file_read_error_callback, cf);
bufferevent_enable(cf->event, EV_READ);
return;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
}
/* Handle a write ready message (server). */
void
file_write_ready(struct client_files *files, struct imsg *imsg)
{
struct msg_write_ready *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_WRITE_READY size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
if (msg->error != 0) {
cf->error = msg->error;
file_fire_done(cf);
} else
file_push(cf);
}
/* Handle read data message (server). */
void
file_read_data(struct client_files *files, struct imsg *imsg)
{
struct msg_read_data *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
void *bdata = msg + 1;
size_t bsize = msglen - sizeof *msg;
if (msglen < sizeof *msg)
fatalx("bad MSG_READ_DATA size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
log_debug("file %d read %zu bytes", cf->stream, bsize);
if (cf->error == 0) {
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
cf->error = ENOMEM;
file_fire_done(cf);
} else
file_fire_read(cf);
}
}
/* Handle a read done message (server). */
void
file_read_done(struct client_files *files, struct imsg *imsg)
{
struct msg_read_done *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_READ_DONE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
log_debug("file %d read done", cf->stream);
cf->error = msg->error;
file_fire_done(cf);
}

View File

@@ -157,14 +157,13 @@ format_draw_put_list(struct screen_write_ctx *octx,
static void static void
format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right, u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *abs_centre, struct format_ranges *frs) struct format_ranges *frs)
{ {
u_int width_left, width_centre, width_right, width_abs_centre; u_int width_left, width_centre, width_right;
width_left = left->cx; width_left = left->cx;
width_centre = centre->cx; width_centre = centre->cx;
width_right = right->cx; width_right = right->cx;
width_abs_centre = abs_centre->cx;
/* /*
* Try to keep as much of the left and right as possible at the expense * Try to keep as much of the left and right as possible at the expense
@@ -200,34 +199,23 @@ format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
- width_centre / 2, - width_centre / 2,
centre->cx / 2 - width_centre / 2, centre->cx / 2 - width_centre / 2,
width_centre); width_centre);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
} }
/* Draw format with list on the left. */ /* Draw format with list on the left. */
static void static void
format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right, u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *abs_centre, struct screen *list, struct screen *list_left, struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *list_right, struct screen *after, int focus_start, struct screen *after, int focus_start, int focus_end,
int focus_end, struct format_ranges *frs) struct format_ranges *frs)
{ {
u_int width_left, width_centre, width_right; u_int width_left, width_centre, width_right;
u_int width_list, width_after, width_abs_centre; u_int width_list, width_after;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
width_left = left->cx; width_left = left->cx;
width_centre = centre->cx; width_centre = centre->cx;
width_right = right->cx; width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx; width_list = list->cx;
width_after = after->cx; width_after = after->cx;
@@ -254,12 +242,12 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */ /* If there is no list left, pass off to the no list function. */
if (width_list == 0) { if (width_list == 0) {
screen_write_start(&ctx, left); screen_write_start(&ctx, NULL, left);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1); screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx); screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre, format_draw_none(octx, available, ocx, ocy, left, centre,
right, abs_centre, frs); right, frs);
return; return;
} }
@@ -303,34 +291,23 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
focus_start = focus_end = 0; focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, width_left, width_list, list, format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
list_left, list_right, focus_start, focus_end, frs); list_left, list_right, focus_start, focus_end, frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
} }
/* Draw format with list in the centre. */ /* Draw format with list in the centre. */
static void static void
format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right, u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *abs_centre, struct screen *list, struct screen *list_left, struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *list_right, struct screen *after, int focus_start, struct screen *after, int focus_start, int focus_end,
int focus_end, struct format_ranges *frs) struct format_ranges *frs)
{ {
u_int width_left, width_centre, width_right, middle; u_int width_left, width_centre, width_right;
u_int width_list, width_after, width_abs_centre; u_int width_list, width_after, middle;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
width_left = left->cx; width_left = left->cx;
width_centre = centre->cx; width_centre = centre->cx;
width_right = right->cx; width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx; width_list = list->cx;
width_after = after->cx; width_after = after->cx;
@@ -357,12 +334,12 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */ /* If there is no list left, pass off to the no list function. */
if (width_list == 0) { if (width_list == 0) {
screen_write_start(&ctx, centre); screen_write_start(&ctx, NULL, centre);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1); screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx); screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre, format_draw_none(octx, available, ocx, ocy, left, centre,
right, abs_centre, frs); right, frs);
return; return;
} }
@@ -411,34 +388,23 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
format_draw_put_list(octx, ocx, ocy, middle - width_list / 2, format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
width_list, list, list_left, list_right, focus_start, focus_end, width_list, list, list_left, list_right, focus_start, focus_end,
frs); frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
} }
/* Draw format with list on the right. */ /* Draw format with list on the right. */
static void static void
format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right, u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *abs_centre, struct screen *list, struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *list_left, struct screen *list_right, struct screen *after, struct screen *after, int focus_start, int focus_end,
int focus_start, int focus_end, struct format_ranges *frs) struct format_ranges *frs)
{ {
u_int width_left, width_centre, width_right; u_int width_left, width_centre, width_right;
u_int width_list, width_after, width_abs_centre; u_int width_list, width_after;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
width_left = left->cx; width_left = left->cx;
width_centre = centre->cx; width_centre = centre->cx;
width_right = right->cx; width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx; width_list = list->cx;
width_after = after->cx; width_after = after->cx;
@@ -465,12 +431,12 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */ /* If there is no list left, pass off to the no list function. */
if (width_list == 0) { if (width_list == 0) {
screen_write_start(&ctx, right); screen_write_start(&ctx, NULL, right);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1); screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx); screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre, format_draw_none(octx, available, ocx, ocy, left, centre,
right, abs_centre, frs); right, frs);
return; return;
} }
@@ -518,130 +484,6 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
format_draw_put_list(octx, ocx, ocy, available - width_list - format_draw_put_list(octx, ocx, ocy, available - width_list -
width_after, width_list, list, list_left, list_right, focus_start, width_after, width_list, list, list_left, list_right, focus_start,
focus_end, frs); focus_end, frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
}
static void
format_draw_absolute_centre(struct screen_write_ctx *octx, u_int available,
u_int ocx, u_int ocy, struct screen *left, struct screen *centre,
struct screen *right, struct screen *abs_centre, struct screen *list,
struct screen *list_left, struct screen *list_right, struct screen *after,
int focus_start, int focus_end, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right, width_abs_centre;
u_int width_list, width_after, middle, abs_centre_offset;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first centre, then the right, then the left.
*/
while (width_left +
width_centre +
width_right > available) {
if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/*
* We trim list after and abs_centre independently, as we are drawing
* them over the rest. Trim first the list, then after the list, then
* abs_centre.
*/
while (width_list + width_after + width_abs_centre > available) {
if (width_list > 0)
width_list--;
else if (width_after > 0)
width_after--;
else
width_abs_centre--;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* Keep writing centre at the relative centre. Only the list is written
* in the absolute centre of the horizontal space.
*/
middle = (width_left + ((available - width_right) - width_left) / 2);
/*
* Write centre at
* middle - width_centre.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
middle - width_centre,
0,
width_centre);
/*
* If there is no focus given, keep the centre in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = list->cx / 2;
/*
* We centre abs_centre and the list together, so their shared centre is
* in the perfect centre of horizontal space.
*/
abs_centre_offset = (available - width_list - width_abs_centre) / 2;
/*
* Write abs_centre before the list.
*/
format_draw_put(octx, ocx, ocy, abs_centre, frs, abs_centre_offset,
0, width_abs_centre);
abs_centre_offset += width_abs_centre;
/*
* Draw the list in the absolute centre
*/
format_draw_put_list(octx, ocx, ocy, abs_centre_offset, width_list,
list, list_left, list_right, focus_start, focus_end, frs);
abs_centre_offset += width_list;
/*
* Write after at the end of the centre
*/
format_draw_put(octx, ocx, ocy, after, frs, abs_centre_offset, 0,
width_after);
}
/* Draw multiple characters. */
static void
format_draw_many(struct screen_write_ctx *ctx, struct style *sy, char ch,
u_int n)
{
u_int i;
utf8_set(&sy->gc.data, ch);
for (i = 0; i < n; i++)
screen_write_cell(ctx, &sy->gc);
} }
/* Draw a format to a screen. */ /* Draw a format to a screen. */
@@ -652,7 +494,6 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
enum { LEFT, enum { LEFT,
CENTRE, CENTRE,
RIGHT, RIGHT,
ABSOLUTE_CENTRE,
LIST, LIST,
LIST_LEFT, LIST_LEFT,
LIST_RIGHT, LIST_RIGHT,
@@ -661,7 +502,6 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
const char *names[] = { "LEFT", const char *names[] = { "LEFT",
"CENTRE", "CENTRE",
"RIGHT", "RIGHT",
"ABSOLUTE_CENTRE",
"LIST", "LIST",
"LIST_LEFT", "LIST_LEFT",
"LIST_RIGHT", "LIST_RIGHT",
@@ -669,14 +509,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
size_t size = strlen(expanded); size_t size = strlen(expanded);
struct screen *os = octx->s, s[TOTAL]; struct screen *os = octx->s, s[TOTAL];
struct screen_write_ctx ctx[TOTAL]; struct screen_write_ctx ctx[TOTAL];
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL]; u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
u_int map[] = { LEFT, u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
LEFT,
CENTRE,
RIGHT,
ABSOLUTE_CENTRE };
int focus_start = -1, focus_end = -1; int focus_start = -1, focus_end = -1;
int list_state = -1, fill = -1, even; int list_state = -1, fill = -1;
enum style_align list_align = STYLE_ALIGN_DEFAULT; enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct grid_cell gc, current_default; struct grid_cell gc, current_default;
struct style sy, saved_sy; struct style sy, saved_sy;
@@ -700,7 +536,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/ */
for (i = 0; i < TOTAL; i++) { for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0); screen_init(&s[i], size, 1, 0);
screen_write_start(&ctx[i], &s[i]); screen_write_start(&ctx[i], NULL, &s[i]);
screen_write_clearendofline(&ctx[i], current_default.bg); screen_write_clearendofline(&ctx[i], current_default.bg);
width[i] = 0; width[i] = 0;
} }
@@ -711,39 +547,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/ */
cp = expanded; cp = expanded;
while (*cp != '\0') { while (*cp != '\0') {
/* Handle sequences of #. */ if (cp[0] != '#' || cp[1] != '[') {
if (cp[0] == '#' && cp[1] != '[' && cp[1] != '\0') {
for (n = 1; cp[n] == '#'; n++)
/* nothing */;
even = ((n % 2) == 0);
if (cp[n] != '[') {
cp += n;
if (even)
n = (n / 2);
else
n = (n / 2) + 1;
width[current] += n;
format_draw_many(&ctx[current], &sy, '#', n);
continue;
}
if (even)
cp += (n + 1);
else
cp += (n - 1);
if (sy.ignore)
continue;
format_draw_many(&ctx[current], &sy, '#', n / 2);
width[current] += (n / 2);
if (even) {
utf8_set(ud, '[');
screen_write_cell(&ctx[current], &sy.gc);
width[current]++;
}
continue;
}
/* Is this not a style? */
if (cp[0] != '#' || cp[1] != '[' || sy.ignore) {
/* See if this is a UTF-8 character. */ /* See if this is a UTF-8 character. */
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) { if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE) while (*++cp != '\0' && more == UTF8_MORE)
@@ -796,8 +600,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
/* If this style pushed or popped the default, update it. */ /* If this style pushed or popped the default, update it. */
if (sy.default_type == STYLE_DEFAULT_PUSH) { if (sy.default_type == STYLE_DEFAULT_PUSH) {
memcpy(&current_default, &saved_sy.gc, memcpy(&current_default, &saved_sy.gc, sizeof current_default);
sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE; sy.default_type = STYLE_DEFAULT_BASE;
} else if (sy.default_type == STYLE_DEFAULT_POP) { } else if (sy.default_type == STYLE_DEFAULT_POP) {
memcpy(&current_default, base, sizeof current_default); memcpy(&current_default, base, sizeof current_default);
@@ -935,41 +738,31 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
/* /*
* Draw the screens. How they are arranged depends on where the list * Draw the screens. How they are arranged depends on where the list
* appears. * appearsq.
*/ */
switch (list_align) { switch (list_align) {
case STYLE_ALIGN_DEFAULT: case STYLE_ALIGN_DEFAULT:
/* No list. */ /* No list. */
format_draw_none(octx, available, ocx, ocy, &s[LEFT], format_draw_none(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &frs); &s[CENTRE], &s[RIGHT], &frs);
break; break;
case STYLE_ALIGN_LEFT: case STYLE_ALIGN_LEFT:
/* List is part of the left. */ /* List is part of the left. */
format_draw_left(octx, available, ocx, ocy, &s[LEFT], format_draw_left(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
focus_start, focus_end, &frs);
break; break;
case STYLE_ALIGN_CENTRE: case STYLE_ALIGN_CENTRE:
/* List is part of the centre. */ /* List is part of the centre. */
format_draw_centre(octx, available, ocx, ocy, &s[LEFT], format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
focus_start, focus_end, &frs);
break; break;
case STYLE_ALIGN_RIGHT: case STYLE_ALIGN_RIGHT:
/* List is part of the right. */ /* List is part of the right. */
format_draw_right(octx, available, ocx, ocy, &s[LEFT], format_draw_right(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST], &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER], &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_ABSOLUTE_CENTRE:
/* List is in the centre of the entire horizontal space. */
format_draw_absolute_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER],
focus_start, focus_end, &frs);
break; break;
} }
@@ -1002,36 +795,16 @@ u_int
format_width(const char *expanded) format_width(const char *expanded)
{ {
const char *cp, *end; const char *cp, *end;
u_int n, width = 0; u_int width = 0;
struct utf8_data ud; struct utf8_data ud;
enum utf8_state more; enum utf8_state more;
cp = expanded; cp = expanded;
while (*cp != '\0') { while (*cp != '\0') {
if (*cp == '#') { if (cp[0] == '#' && cp[1] == '[') {
for (n = 1; cp[n] == '#'; n++)
/* nothing */;
if (cp[n] != '[') {
width += n;
cp += n;
continue;
}
width += (n / 2); /* one for each ## */
if ((n % 2) == 0) {
/*
* An even number of #s means that all #s are
* escaped, so not a style.
*/
width++; /* one for the [ */
cp += (n + 1);
continue;
}
cp += (n - 1); /* point to the [ */
end = format_skip(cp + 2, "]"); end = format_skip(cp + 2, "]");
if (end == NULL) if (end == NULL)
return (0); return 0;
cp = end + 1; cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) { } else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE) while (*++cp != '\0' && more == UTF8_MORE)
@@ -1049,57 +822,19 @@ format_width(const char *expanded)
return (width); return (width);
} }
/* /* Trim on the left, taking #[] into account. */
* Trim on the left, taking #[] into account. Note, we copy the whole set of
* unescaped #s, but only add their escaped size to width. This is because the
* format_draw function will actually do the escaping when it runs
*/
char * char *
format_trim_left(const char *expanded, u_int limit) format_trim_left(const char *expanded, u_int limit)
{ {
char *copy, *out; char *copy, *out;
const char *cp = expanded, *end; const char *cp = expanded, *end;
u_int even, n, width = 0; u_int width = 0;
struct utf8_data ud; struct utf8_data ud;
enum utf8_state more; enum utf8_state more;
out = copy = xcalloc(1, strlen(expanded) + 1); out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') { while (*cp != '\0') {
if (width >= limit) if (cp[0] == '#' && cp[1] == '[') {
break;
if (*cp == '#') {
for (end = cp + 1; *end == '#'; end++)
/* nothing */;
n = end - cp;
if (*end != '[') {
if (n > limit - width)
n = limit - width;
memcpy(out, cp, n);
out += n;
width += n;
cp = end;
continue;
}
even = ((n % 2) == 0);
n /= 2;
if (n > limit - width)
n = limit - width;
width += n;
n *= 2;
memcpy(out, cp, n);
out += n;
if (even) {
if (width + 1 <= limit) {
*out++ = '[';
width++;
}
cp = end + 1;
continue;
}
cp = end - 1;
end = format_skip(cp + 2, "]"); end = format_skip(cp + 2, "]");
if (end == NULL) if (end == NULL)
break; break;
@@ -1137,7 +872,7 @@ format_trim_right(const char *expanded, u_int limit)
{ {
char *copy, *out; char *copy, *out;
const char *cp = expanded, *end; const char *cp = expanded, *end;
u_int width = 0, total_width, skip, old_n, even, n; u_int width = 0, total_width, skip;
struct utf8_data ud; struct utf8_data ud;
enum utf8_state more; enum utf8_state more;
@@ -1146,64 +881,12 @@ format_trim_right(const char *expanded, u_int limit)
return (xstrdup(expanded)); return (xstrdup(expanded));
skip = total_width - limit; skip = total_width - limit;
out = copy = xcalloc(1, strlen(expanded) + 1); out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') { while (*cp != '\0') {
if (*cp == '#') { if (cp[0] == '#' && cp[1] == '[') {
for (end = cp + 1; *end == '#'; end++)
/* nothing */;
old_n = n = end - cp;
if (*end != '[') {
if (width <= skip) {
if (skip - width >= n)
n = 0;
else
n -= (skip - width);
}
if (n != 0) {
memcpy(out, cp, n);
out += n;
}
/*
* The width always increases by the full
* amount even if we can't copy anything yet.
*/
width += old_n;
cp = end;
continue;
}
even = ((n % 2) == 0);
n /= 2;
if (width <= skip) {
if (skip - width >= n)
n = 0;
else
n -= (skip - width);
}
if (n != 0) {
/*
* Copy the full amount because it hasn't been
* escaped yet.
*/
memcpy(out, cp, old_n);
out += old_n;
}
cp += old_n;
width += (old_n / 2) - even;
if (even) {
if (width > skip)
*out++ = '[';
width++;
continue;
}
cp = end - 1;
end = format_skip(cp + 2, "]"); end = format_skip(cp + 2, "]");
if (end == NULL) { if (end == NULL)
break; break;
}
memcpy(out, cp, end + 1 - cp); memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp); out += (end + 1 - cp);
cp = end + 1; cp = end + 1;

3844
format.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +0,0 @@
/*
* Copyright (c) 2020 Sergey Nizovtsev <snizovtsev@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 <stddef.h>
#include <assert.h>
#include "tmux.h"
#define FUZZER_MAXLEN 512
#define PANE_WIDTH 80
#define PANE_HEIGHT 25
struct event_base *libevent;
int
LLVMFuzzerTestOneInput(const unsigned char *data, size_t size)
{
struct bufferevent *vpty[2];
struct window *w;
struct window_pane *wp;
int error;
/*
* Since AFL doesn't support -max_len paramenter we have to
* discard long inputs manually.
*/
if (size > FUZZER_MAXLEN)
return 0;
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
wp = window_add_pane(w, NULL, 0, 0);
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
wp->ictx = input_init(wp, vpty[0]);
window_add_ref(w, __func__);
input_parse_buffer(wp, (u_char*) data, size);
while (cmdq_next(NULL) != 0)
;
error = event_base_loop(libevent, EVLOOP_NONBLOCK);
if (error == -1)
errx(1, "event_base_loop failed");
assert(w->references == 1);
window_remove_ref(w, __func__);
bufferevent_free(vpty[0]);
bufferevent_free(vpty[1]);
return 0;
}
int
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
{
const struct options_table_entry *oe;
global_environ = environ_create();
global_options = options_create(NULL);
global_s_options = options_create(NULL);
global_w_options = options_create(NULL);
for (oe = options_table; oe->name != NULL; oe++) {
if (oe->scope & OPTIONS_TABLE_SERVER)
options_default(global_options, oe);
if (oe->scope & OPTIONS_TABLE_SESSION)
options_default(global_s_options, oe);
if (oe->scope & OPTIONS_TABLE_WINDOW)
options_default(global_w_options, oe);
}
libevent = osdep_event_init();
options_set_number(global_w_options, "monitor-bell", 0);
options_set_number(global_w_options, "allow-rename", 1);
options_set_number(global_options, "set-clipboard", 2);
return 0;
}

View File

@@ -1,8 +0,0 @@
"\x1b["
"1000"
"2004"
"1049"
"38;2"
"100;"
"tmux;"
"rgb:00/00/00"

View File

@@ -1,2 +0,0 @@
[libfuzzer]
max_len = 512

View File

@@ -1,389 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.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 "tmux.h"
#include <string.h>
/* Initialise virtual cursor. */
void
grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
{
gr->gd = gd;
gr->cx = cx;
gr->cy = cy;
}
/* Get cursor position from reader. */
void
grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
{
*cx = gr->cx;
*cy = gr->cy;
}
/* Get length of line containing the cursor. */
u_int
grid_reader_line_length(struct grid_reader *gr)
{
return (grid_line_length(gr->gd, gr->cy));
}
/* Move cursor forward one position. */
void
grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
{
u_int px;
struct grid_cell gc;
if (all)
px = gr->gd->sx;
else
px = grid_reader_line_length(gr);
if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
grid_reader_cursor_start_of_line(gr, 0);
grid_reader_cursor_down(gr);
} else if (gr->cx < px) {
gr->cx++;
while (gr->cx < px) {
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
gr->cx++;
}
}
}
/* Move cursor back one position. */
void
grid_reader_cursor_left(struct grid_reader *gr, int wrap)
{
struct grid_cell gc;
while (gr->cx > 0) {
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
gr->cx--;
}
if (gr->cx == 0 && gr->cy > 0 &&
(wrap ||
grid_get_line(gr->gd, gr->cy - 1)->flags & GRID_LINE_WRAPPED)) {
grid_reader_cursor_up(gr);
grid_reader_cursor_end_of_line(gr, 0, 0);
} else if (gr->cx > 0)
gr->cx--;
}
/* Move cursor down one line. */
void
grid_reader_cursor_down(struct grid_reader *gr)
{
struct grid_cell gc;
if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
gr->cy++;
while (gr->cx > 0) {
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
gr->cx--;
}
}
/* Move cursor up one line. */
void
grid_reader_cursor_up(struct grid_reader *gr)
{
struct grid_cell gc;
if (gr->cy > 0)
gr->cy--;
while (gr->cx > 0) {
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
gr->cx--;
}
}
/* Move cursor to the start of the line. */
void
grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
{
if (wrap) {
while (gr->cy > 0 &&
grid_get_line(gr->gd, gr->cy - 1)->flags &
GRID_LINE_WRAPPED)
gr->cy--;
}
gr->cx = 0;
}
/* Move cursor to the end of the line. */
void
grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
{
u_int yy;
if (wrap) {
yy = gr->gd->hsize + gr->gd->sy - 1;
while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
GRID_LINE_WRAPPED)
gr->cy++;
}
if (all)
gr->cx = gr->gd->sx;
else
gr->cx = grid_reader_line_length(gr);
}
/* Check if character under cursor is in set. */
int
grid_reader_in_set(struct grid_reader *gr, const char *set)
{
struct grid_cell gc;
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (gc.flags & GRID_FLAG_PADDING)
return (0);
return (utf8_cstrhas(set, &gc.data));
}
/* Move cursor to the start of the next word. */
void
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
{
u_int xx, yy;
int expected = 0;
/* Do not break up wrapped words. */
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
xx = gr->gd->sx - 1;
else
xx = grid_reader_line_length(gr);
yy = gr->gd->hsize + gr->gd->sy - 1;
/*
* If we started inside a word, skip over word characters. Then skip
* over separators till the next word.
*
* expected is initially set to 0 for the former and then 1 for the
* latter. It is finally set to 0 when the beginning of the next word is
* found.
*/
do {
while (gr->cx > xx ||
grid_reader_in_set(gr, separators) == expected) {
/* Move down if we are past the end of the line. */
if (gr->cx > xx) {
if (gr->cy == yy)
return;
grid_reader_cursor_start_of_line(gr, 0);
grid_reader_cursor_down(gr);
if (grid_get_line(gr->gd, gr->cy)->flags &
GRID_LINE_WRAPPED)
xx = gr->gd->sx - 1;
else
xx = grid_reader_line_length(gr);
} else
gr->cx++;
}
expected = !expected;
} while (expected == 1);
}
/* Move cursor to the end of the next word. */
void
grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
{
u_int xx, yy;
int expected = 1;
/* Do not break up wrapped words. */
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
xx = gr->gd->sx - 1;
else
xx = grid_reader_line_length(gr);
yy = gr->gd->hsize + gr->gd->sy - 1;
/*
* If we started on a separator, skip over separators. Then skip over
* word characters till the next separator.
*
* expected is initially set to 1 for the former and then 1 for the
* latter. It is finally set to 1 when the end of the next word is
* found.
*/
do {
while (gr->cx > xx ||
grid_reader_in_set(gr, separators) == expected) {
/* Move down if we are past the end of the line. */
if (gr->cx > xx) {
if (gr->cy == yy)
return;
grid_reader_cursor_start_of_line(gr, 0);
grid_reader_cursor_down(gr);
if (grid_get_line(gr->gd, gr->cy)->flags &
GRID_LINE_WRAPPED)
xx = gr->gd->sx - 1;
else
xx = grid_reader_line_length(gr);
} else
gr->cx++;
}
expected = !expected;
} while (expected == 0);
}
/* Move to the previous place where a word begins. */
void
grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
int already)
{
int oldx, oldy, r;
/* Move back to the previous word character. */
if (already || grid_reader_in_set(gr, separators)) {
for (;;) {
if (gr->cx > 0) {
gr->cx--;
if (!grid_reader_in_set(gr, separators))
break;
} else {
if (gr->cy == 0)
return;
grid_reader_cursor_up(gr);
grid_reader_cursor_end_of_line(gr, 0, 0);
/* Stop if separator at EOL. */
if (gr->cx > 0) {
oldx = gr->cx;
gr->cx--;
r = grid_reader_in_set(gr, separators);
gr->cx = oldx;
if (r)
break;
}
}
}
}
/* Move back to the beginning of this word. */
do {
oldx = gr->cx;
oldy = gr->cy;
if (gr->cx == 0) {
if (gr->cy == 0 ||
~grid_get_line(gr->gd, gr->cy - 1)->flags &
GRID_LINE_WRAPPED)
break;
grid_reader_cursor_up(gr);
grid_reader_cursor_end_of_line(gr, 0, 1);
}
if (gr->cx > 0)
gr->cx--;
} while (!grid_reader_in_set(gr, separators));
gr->cx = oldx;
gr->cy = oldy;
}
/* Jump forward to character. */
int
grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
{
struct grid_cell gc;
u_int px, py, xx, yy;
px = gr->cx;
yy = gr->gd->hsize + gr->gd->sy - 1;
for (py = gr->cy; py <= yy; py++) {
xx = grid_line_length(gr->gd, py);
while (px < xx) {
grid_get_cell(gr->gd, px, py, &gc);
if (!(gc.flags & GRID_FLAG_PADDING) &&
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px;
gr->cy = py;
return 1;
}
px++;
}
if (py == yy ||
!(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
return 0;
px = 0;
}
return 0;
}
/* Jump back to character. */
int
grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
{
struct grid_cell gc;
u_int px, py, xx;
xx = gr->cx + 1;
for (py = gr->cy + 1; py > 0; py--) {
for (px = xx; px > 0; px--) {
grid_get_cell(gr->gd, px - 1, py - 1, &gc);
if (!(gc.flags & GRID_FLAG_PADDING) &&
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px - 1;
gr->cy = py - 1;
return 1;
}
}
if (py == 1 ||
!(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
return 0;
xx = grid_line_length(gr->gd, py - 2);
}
return 0;
}
/* Jump back to the first non-blank character of the line. */
void
grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
{
struct grid_cell gc;
u_int px, py, xx, yy;
yy = gr->gd->hsize + gr->gd->sy - 1;
grid_reader_cursor_start_of_line(gr, 1);
for (py = gr->cy; py <= yy; py++) {
xx = grid_line_length(gr->gd, py);
for (px = 0; px < xx; px++) {
grid_get_cell(gr->gd, px, py, &gc);
if (gc.data.size != 1 || *gc.data.data != ' ')
break;
}
if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
break;
}
}

View File

@@ -45,13 +45,6 @@ grid_view_set_cell(struct grid *gd, u_int px, u_int py,
grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc);
} }
/* Set padding. */
void
grid_view_set_padding(struct grid *gd, u_int px, u_int py)
{
grid_set_padding(gd, grid_view_x(gd, px), grid_view_y(gd, py));
}
/* Set cells. */ /* Set cells. */
void void
grid_view_set_cells(struct grid *gd, u_int px, u_int py, grid_view_set_cells(struct grid *gd, u_int px, u_int py,

181
grid.c
View File

@@ -40,22 +40,16 @@ const struct grid_cell grid_default_cell = {
{ { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0 { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0
}; };
/*
* Padding grid cell data. Padding cells are the only zero width cell that
* appears in the grid - because of this, they are always extended cells.
*/
static const struct grid_cell grid_padding_cell = {
{ { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 0
};
/* Cleared grid cell data. */ /* Cleared grid cell data. */
static const struct grid_cell grid_cleared_cell = { const struct grid_cell grid_cleared_cell = {
{ { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0 { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0
}; };
static const struct grid_cell_entry grid_cleared_entry = { static const struct grid_cell_entry grid_cleared_entry = {
GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } } GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
}; };
static void grid_empty_line(struct grid *, u_int, u_int);
/* Store cell in entry. */ /* Store cell in entry. */
static void static void
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc, grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
@@ -108,13 +102,12 @@ grid_get_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
} }
/* Set cell as extended. */ /* Set cell as extended. */
static struct grid_extd_entry * static struct grid_cell *
grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce, grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
const struct grid_cell *gc) const struct grid_cell *gc)
{ {
struct grid_extd_entry *gee; struct grid_cell *gcp;
int flags = (gc->flags & ~GRID_FLAG_CLEARED); int flags = (gc->flags & ~GRID_FLAG_CLEARED);
utf8_char uc;
if (~gce->flags & GRID_FLAG_EXTENDED) if (~gce->flags & GRID_FLAG_EXTENDED)
grid_get_extended_cell(gl, gce, flags); grid_get_extended_cell(gl, gce, flags);
@@ -122,16 +115,10 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
fatalx("offset too big"); fatalx("offset too big");
gl->flags |= GRID_LINE_EXTENDED; gl->flags |= GRID_LINE_EXTENDED;
utf8_from_data(&gc->data, &uc); gcp = &gl->extddata[gce->offset];
memcpy(gcp, gc, sizeof *gcp);
gee = &gl->extddata[gce->offset]; gcp->flags = flags;
gee->data = uc; return (gcp);
gee->attr = gc->attr;
gee->flags = flags;
gee->fg = gc->fg;
gee->bg = gc->bg;
gee->us = gc->us;
return (gee);
} }
/* Free up unused extended cells. */ /* Free up unused extended cells. */
@@ -139,9 +126,9 @@ static void
grid_compact_line(struct grid_line *gl) grid_compact_line(struct grid_line *gl)
{ {
int new_extdsize = 0; int new_extdsize = 0;
struct grid_extd_entry *new_extddata; struct grid_cell *new_extddata;
struct grid_cell_entry *gce; struct grid_cell_entry *gce;
struct grid_extd_entry *gee; struct grid_cell *gc;
u_int px, idx; u_int px, idx;
if (gl->extdsize == 0) if (gl->extdsize == 0)
@@ -165,8 +152,8 @@ grid_compact_line(struct grid_line *gl)
for (px = 0; px < gl->cellsize; px++) { for (px = 0; px < gl->cellsize; px++) {
gce = &gl->celldata[px]; gce = &gl->celldata[px];
if (gce->flags & GRID_FLAG_EXTENDED) { if (gce->flags & GRID_FLAG_EXTENDED) {
gee = &gl->extddata[gce->offset]; gc = &gl->extddata[gce->offset];
memcpy(&new_extddata[idx], gee, sizeof *gee); memcpy(&new_extddata[idx], gc, sizeof *gc);
gce->offset = idx++; gce->offset = idx++;
} }
} }
@@ -196,14 +183,17 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
{ {
struct grid_line *gl = &gd->linedata[py]; struct grid_line *gl = &gd->linedata[py];
struct grid_cell_entry *gce = &gl->celldata[px]; struct grid_cell_entry *gce = &gl->celldata[px];
struct grid_extd_entry *gee; struct grid_cell *gc;
memcpy(gce, &grid_cleared_entry, sizeof *gce); memcpy(gce, &grid_cleared_entry, sizeof *gce);
if (bg != 8) { if (bg != 8) {
if (bg & COLOUR_FLAG_RGB) { if (bg & COLOUR_FLAG_RGB) {
grid_get_extended_cell(gl, gce, gce->flags); grid_get_extended_cell(gl, gce, gce->flags);
gee = grid_extended_cell(gl, gce, &grid_cleared_cell); gl->flags |= GRID_LINE_EXTENDED;
gee->bg = bg;
gc = &gl->extddata[gce->offset];
memcpy(gc, &grid_cleared_cell, sizeof *gc);
gc->bg = bg;
} else { } else {
if (bg & COLOUR_FLAG_256) if (bg & COLOUR_FLAG_256)
gce->flags |= GRID_FLAG_BG256; gce->flags |= GRID_FLAG_BG256;
@@ -223,28 +213,19 @@ grid_check_y(struct grid *gd, const char *from, u_int py)
return (0); return (0);
} }
/* Check if two styles are (visibly) the same. */
int
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
return (0);
if (gc1->attr != gc2->attr || gc1->flags != gc2->flags)
return (0);
return (1);
}
/* Compare grid cells. Return 1 if equal, 0 if not. */ /* Compare grid cells. Return 1 if equal, 0 if not. */
int int
grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) grid_cells_equal(const struct grid_cell *gca, const struct grid_cell *gcb)
{ {
if (!grid_cells_look_equal(gc1, gc2)) if (gca->fg != gcb->fg || gca->bg != gcb->bg)
return (0); return (0);
if (gc1->data.width != gc2->data.width) if (gca->attr != gcb->attr || gca->flags != gcb->flags)
return (0); return (0);
if (gc1->data.size != gc2->data.size) if (gca->data.width != gcb->data.width)
return (0); return (0);
return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0); if (gca->data.size != gcb->data.size)
return (0);
return (memcmp(gca->data.data, gcb->data.data, gca->data.size) == 0);
} }
/* Free one line. */ /* Free one line. */
@@ -277,10 +258,7 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
gd->sx = sx; gd->sx = sx;
gd->sy = sy; gd->sy = sy;
if (hlimit != 0) gd->flags = GRID_HISTORY;
gd->flags = GRID_HISTORY;
else
gd->flags = 0;
gd->hscrolled = 0; gd->hscrolled = 0;
gd->hsize = 0; gd->hsize = 0;
@@ -370,19 +348,6 @@ grid_collect_history(struct grid *gd)
gd->hscrolled = gd->hsize; gd->hscrolled = gd->hsize;
} }
/* Remove lines from the bottom of the history. */
void
grid_remove_history(struct grid *gd, u_int ny)
{
u_int yy;
if (ny > gd->hsize)
return;
for (yy = 0; yy < ny; yy++)
grid_free_line(gd, gd->hsize + gd->sy - 1 - yy);
gd->hsize -= ny;
}
/* /*
* Scroll the entire visible screen, moving one line into the history. Just * Scroll the entire visible screen, moving one line into the history. Just
* allocate a new line at the bottom and move the history size indicator. * allocate a new line at the bottom and move the history size indicator.
@@ -463,7 +428,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
sx = gd->sx / 4; sx = gd->sx / 4;
else if (sx < gd->sx / 2) else if (sx < gd->sx / 2)
sx = gd->sx / 2; sx = gd->sx / 2;
else if (gd->sx > sx) else
sx = gd->sx; sx = gd->sx;
gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata); gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata);
@@ -473,7 +438,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
} }
/* Empty a line and set background colour if needed. */ /* Empty a line and set background colour if needed. */
void static void
grid_empty_line(struct grid *gd, u_int py, u_int bg) grid_empty_line(struct grid *gd, u_int py, u_int bg)
{ {
memset(&gd->linedata[py], 0, sizeof gd->linedata[py]); memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
@@ -495,20 +460,12 @@ static void
grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc) grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
{ {
struct grid_cell_entry *gce = &gl->celldata[px]; struct grid_cell_entry *gce = &gl->celldata[px];
struct grid_extd_entry *gee;
if (gce->flags & GRID_FLAG_EXTENDED) { if (gce->flags & GRID_FLAG_EXTENDED) {
if (gce->offset >= gl->extdsize) if (gce->offset >= gl->extdsize)
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
else { else
gee = &gl->extddata[gce->offset]; memcpy(gc, &gl->extddata[gce->offset], sizeof *gc);
gc->flags = gee->flags;
gc->attr = gee->attr;
gc->fg = gee->fg;
gc->bg = gee->bg;
gc->us = gee->us;
utf8_to_data(gee->data, &gc->data);
}
return; return;
} }
@@ -535,7 +492,7 @@ grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
grid_get_cell1(&gd->linedata[py], px, gc); grid_get_cell1(&gd->linedata[py], px, gc);
} }
/* Set cell at position. */ /* Set cell at relative position. */
void void
grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
{ {
@@ -558,21 +515,14 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
grid_store_cell(gce, gc, gc->data.data[0]); grid_store_cell(gce, gc, gc->data.data[0]);
} }
/* Set padding at position. */ /* Set cells at relative position. */
void
grid_set_padding(struct grid *gd, u_int px, u_int py)
{
grid_set_cell(gd, px, py, &grid_padding_cell);
}
/* Set cells at position. */
void void
grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc, grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
const char *s, size_t slen) const char *s, size_t slen)
{ {
struct grid_line *gl; struct grid_line *gl;
struct grid_cell_entry *gce; struct grid_cell_entry *gce;
struct grid_extd_entry *gee; struct grid_cell *gcp;
u_int i; u_int i;
if (grid_check_y(gd, __func__, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
@@ -587,8 +537,8 @@ grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
for (i = 0; i < slen; i++) { for (i = 0; i < slen; i++) {
gce = &gl->celldata[px + i]; gce = &gl->celldata[px + i];
if (grid_need_extended_cell(gce, gc)) { if (grid_need_extended_cell(gce, gc)) {
gee = grid_extended_cell(gl, gce, gc); gcp = grid_extended_cell(gl, gce, gc);
gee->data = utf8_build_one(s[i]); utf8_set(&gcp->data, s[i]);
} else } else
grid_store_cell(gce, gc, s[i]); grid_store_cell(gce, gc, s[i]);
} }
@@ -652,8 +602,6 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
grid_free_line(gd, yy); grid_free_line(gd, yy);
grid_empty_line(gd, yy, bg); grid_empty_line(gd, yy, bg);
} }
if (py != 0)
gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
} }
/* Move a group of lines. */ /* Move a group of lines. */
@@ -680,8 +628,6 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
continue; continue;
grid_free_line(gd, yy); grid_free_line(gd, yy);
} }
if (dy != 0)
gd->linedata[dy - 1].flags &= ~GRID_LINE_WRAPPED;
memmove(&gd->linedata[dy], &gd->linedata[py], memmove(&gd->linedata[dy], &gd->linedata[py],
ny * (sizeof *gd->linedata)); ny * (sizeof *gd->linedata));
@@ -694,8 +640,6 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
if (yy < dy || yy >= dy + ny) if (yy < dy || yy >= dy + ny)
grid_empty_line(gd, yy, bg); grid_empty_line(gd, yy, bg);
} }
if (py != 0 && (py < dy || py >= dy + ny))
gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
} }
/* Move a group of cells. */ /* Move a group of cells. */
@@ -811,15 +755,15 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
case 8: case 8:
values[n++] = 49; values[n++] = 49;
break; break;
case 90: case 100:
case 91: case 101:
case 92: case 102:
case 93: case 103:
case 94: case 104:
case 95: case 105:
case 96: case 106:
case 97: case 107:
values[n++] = gc->bg + 10; values[n++] = gc->bg - 10;
break; break;
} }
} }
@@ -1045,14 +989,14 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
srcl->cellsize * sizeof *dstl->celldata); srcl->cellsize * sizeof *dstl->celldata);
} else } else
dstl->celldata = NULL; dstl->celldata = NULL;
if (srcl->extdsize != 0) { if (srcl->extdsize != 0) {
dstl->extdsize = srcl->extdsize; dstl->extdsize = srcl->extdsize;
dstl->extddata = xreallocarray(NULL, dstl->extdsize, dstl->extddata = xreallocarray(NULL, dstl->extdsize,
sizeof *dstl->extddata); sizeof *dstl->extddata);
memcpy(dstl->extddata, srcl->extddata, dstl->extdsize * memcpy(dstl->extddata, srcl->extddata, dstl->extdsize *
sizeof *dstl->extddata); sizeof *dstl->extddata);
} else }
dstl->extddata = NULL;
sy++; sy++;
dy++; dy++;
@@ -1276,7 +1220,7 @@ grid_reflow(struct grid *gd, u_int sx)
struct grid *target; struct grid *target;
struct grid_line *gl; struct grid_line *gl;
struct grid_cell gc; struct grid_cell gc;
u_int yy, width, i, at; u_int yy, width, i, at, first;
/* /*
* Create a destination grid. This is just used as a container for the * Create a destination grid. This is just used as a container for the
@@ -1293,12 +1237,13 @@ grid_reflow(struct grid *gd, u_int sx)
continue; continue;
/* /*
* Work out the width of this line. at is the point at which * Work out the width of this line. first is the width of the
* the available width is hit, and width is the full line * first character, at is the point at which the available
* width. * width is hit, and width is the full line width.
*/ */
at = width = 0; first = at = width = 0;
if (~gl->flags & GRID_LINE_EXTENDED) { if (~gl->flags & GRID_LINE_EXTENDED) {
first = 1;
width = gl->cellused; width = gl->cellused;
if (width > sx) if (width > sx)
at = sx; at = sx;
@@ -1307,6 +1252,8 @@ grid_reflow(struct grid *gd, u_int sx)
} else { } else {
for (i = 0; i < gl->cellused; i++) { for (i = 0; i < gl->cellused; i++) {
grid_get_cell1(gl, i, &gc); grid_get_cell1(gl, i, &gc);
if (i == 0)
first = gc.data.width;
if (at == 0 && width + gc.data.width > sx) if (at == 0 && width + gc.data.width > sx)
at = i; at = i;
width += gc.data.width; width += gc.data.width;
@@ -1314,10 +1261,10 @@ grid_reflow(struct grid *gd, u_int sx)
} }
/* /*
* If the line is exactly right, just move it across * If the line is exactly right or the first character is wider
* unchanged. * than the targe width, just move it across unchanged.
*/ */
if (width == sx) { if (width == sx || first > sx) {
grid_reflow_move(target, gl); grid_reflow_move(target, gl);
continue; continue;
} }
@@ -1380,13 +1327,17 @@ grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
void void
grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy) grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
{ {
u_int yy, ay = 0; u_int yy, ax = 0, ay = 0;
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) { for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
if (ay == wy) if (ay == wy)
break; break;
if (~gd->linedata[yy].flags & GRID_LINE_WRAPPED) if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
ax += gd->linedata[yy].cellused;
else {
ax = 0;
ay++; ay++;
}
} }
/* /*
@@ -1421,9 +1372,7 @@ grid_line_length(struct grid *gd, u_int py)
px = gd->sx; px = gd->sx;
while (px > 0) { while (px > 0) {
grid_get_cell(gd, px - 1, py, &gc); grid_get_cell(gd, px - 1, py, &gc);
if ((gc.flags & GRID_FLAG_PADDING) || if (gc.data.size != 1 || *gc.data.data != ' ')
gc.data.size != 1 ||
*gc.data.data != ' ')
break; break;
px--; px--;
} }

Some files were not shown because too many files have changed in this diff Show More