Compare commits

..

No commits in common. "master" and "3.0a" have entirely different histories.
master ... 3.0a

224 changed files with 12655 additions and 50244 deletions

View File

@ -14,8 +14,8 @@ Before opening an issue, please ensure that:
- Your question or issue is not covered [in the
manual](https://man.openbsd.org/tmux.1) (run `man tmux`).
- Your problem is not mentioned in [the CHANGES
file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES).
- Your problem is not mentioned in the [CHANGES
file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES) file.
- Nobody else has opened the same issue recently.
@ -29,7 +29,7 @@ uname -sp && tmux -V && echo $TERM
Also include:
- Your platform (Linux, macOS, or whatever).
- Your platform (Linux, OS X, or whatever).
- A brief description of the problem with steps to reproduce.
@ -37,8 +37,7 @@ Also include:
- Your terminal, and `$TERM` inside and outside of tmux.
- Logs from tmux (see below). Please attach logs to the issue directly rather
than using a download site or pastebin. Put in a zip file if necessary.
- Logs from tmux (see below).
- At most one or two screenshots, if helpful.
@ -77,8 +76,3 @@ The log files are:
- `tmux-out*.log`: output log file.
Please attach the log files to your issue.
## What does it mean if an issue is closed?
All it means is that work on the issue is not planned for the near future. See
the issue's comments to find out if contributions would be welcome.

2
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: nicm
liberapay: tmux

View File

@ -1,12 +1,3 @@
---
name: Use this issue template
about: Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
title: ''
labels: ''
assignees: ''
---
### Issue description
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md

View File

@ -1 +0,0 @@
blank_issues_enabled: false

18
.github/README.md vendored
View File

@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
## Dependencies
@ -14,17 +14,8 @@ page](https://github.com/libevent/libevent/releases/latest).
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
from [this page](https://invisible-mirror.net/archives/ncurses/).
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
## 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
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
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
To get and build the latest from version control - note that this requires
@ -79,9 +67,9 @@ A small example configuration is in `example_tmux.conf`.
And a bash(1) completion file at:
https://github.com/scop/bash-completion/blob/main/completions/tmux
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.
## Support

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

View File

@ -1,34 +0,0 @@
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: '30'
issue-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
pr-inactive-days: '60'
pr-comment: >
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
discussion-inactive-days: '60'
discussion-comment: >
This discussion has been automatically locked since there
has not been any recent activity after it was closed.

25
.gitignore vendored
View File

@ -1,24 +1,21 @@
*.core
*.dSYM
*.diff
*.o
*.patch
*.swp
*~
*.diff
*.patch
*.core
core
tags
.deps/
.dirstamp
Makefile
Makefile.in
compat/.dirstamp
aclocal.m4
autom4te.cache/
cmd-parse.c
compat/.dirstamp
config.log
config.status
configure
core
etc/
fuzz/*-fuzzer
tags
tmux
Makefile
Makefile.in
configure
tmux.1.*
*.dSYM
cmd-parse.c

View File

@ -1,88 +1,16 @@
language: c
os:
- linux
- freebsd
- osx
- linux
- osx
compiler:
- gcc
- 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
- gcc
- clang
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:
- sh .github/travis/build.sh
- ./autogen.sh && ./configure && make

928
CHANGES
View File

@ -1,916 +1,4 @@
CHANGES FROM 3.4 TO 3.5
* Revamp extended keys support to more closely match xterm and support mode 2
as well as mode 1. This is a substantial change to key handling which changes
tmux to always request mode 2 from parent terminal, changes to an unambiguous
internal representation of keys, and adds an option (extended-keys-format) to
control the format similar to the xterm(1) formatOtherKeys resource.
* Clear an overlay (popup or menu) when command prompt is entered.
* Add copy-mode -d flag to scroll a page down if in copy mode already (matching
-e).
* Display hyperlinks in copy mode and add copy_cursor_hyperlink format to get
the hyperlink under the cursor.
* Add a prefix timeout option.
* Mouse move keys are not useful as key bindings because we do not turn them on
unless the application requests them. Ignore them so they do not cause the
prefix to be canceled
* Add search_count and search_count_partial formats in copy mode.
* Do not reset mouse pane if clicked on status line,
* Add mirrored versions of the main-horizontal and main-vertical layouts where
the main pane is bottom or right instead of top or left.
* Allow REP to work with Unicode characters.
* Fix size calculation of terminators for clipboard escape sequences.
* Treat CRLF as LF in config files where it is easy to do so.
* The Linux console has some bugs with bright colours, so add some workarounds
for it.
* If built with systemd, remove some environment variables it uses.
* Adjust the logic when deleting last buffer to better preserve the selection:
if selecting the element below the deleted one fails (because as the last
one), select the one above it instead.
* Add --enable-jemalloc to build with jemalloc memory allocator (since glibc
malloc is so poor).
* Add a way (refresh-client -r) for control mode clients to provide OSC 10 and
11 responses to tmux so they can set the default foreground and background
colours.
* Add N to search backwards in tree modes.
* Use default-shell for command prompt, #() and popups.
* Revert part of a change intended to improve search performance by skipping
parts of lines already searched, but which in fact skipped the ends of lines
altogether.
* Add a command-error hook when a command fails.
* Add an option allow-set-title to forbid applications from changing the pane
title.
* Correct handling of mouse up events (don't ignore all but the last released
button), and always process down event for double click.
* Fix a crash if focusing a pane that is exiting.
* Pick newest session (as documented) when looking for next session for
detach-on-destroy.
* Reduce default escape-time to 10 milliseconds.
* Add display-menu -M to always turn mouse on in a menu.
* Look for feature code 21 for DECSLRM and 28 for DECFRA in the device
attributes and also accept level 1.
* Fix crash if built with SIXEL and the SIXEL colour register is invalid; also
remove SIXEL images before reflow.
* Do not notify window-layout-changed if the window is about to be destroyed.
* Do not consider a selection present if it is empty for the selection_active
and selection_present format variables.
* Fix split-window -p.
CHANGES FROM 3.3a TO 3.4
* Add options keep-last and keep-group to destroy-unattached to keep the last
session whether in a group.
* Don't allow paste-buffer into dead panes.
* Add -t to source-file.
* Rewrite combined character handling to be more consistent and to support
newer Unicode combined characters.
* Add basic support for SIXEL if built with --enable-sixel.
* Add a session, pane and user mouse range types for the status line and add
format variables for mouse_status_line and mouse_status_range so they can be
associated with different commands in the key bindings.
* Add flag (-o) to next-prompt/previous-prompt to go to OSC 133 command output.
* Add options and flags for menu styles (menu-style, menu-border-style) similar
to those existing for popups.
* Add support for marking lines with a shell prompt based on the OSC 133 extension.
* Check for libterminfo for NetBSD.
* Add "us" to styles for underscore colour.
* Add flags (-c and -y) to change the confirm key and default behaviour of
confirm-before.
* Use ncurses' new tparm_s function (added in 6.4-20230424) instead of tparm so
it does not object to string arguments in c apabilities it doesn't already
know. Also ignore errors from tparm if using previous ncurses versions.
* Set default lock command to vlock on Linux if present at build time.
* Discard mouse sequences that have the right form but actually are invalid.
* Add support for spawning panes in separate cgroups with systemd and a
configure flag (--disable-cgroups) to turn off.
* Add a format (pane_unseen_changes) to show if there are unseen changes while
in a mode.
* Remove old buffer when renaming rather than complaining.
* Add an L modifier like P, W, S to loop over clients.
* Add -f to list-clients like the other list commands.
* Extend display-message to work for control clients.
* Add a flag to display-menu to select the manu item selected when the menu is
open.
* Have tmux recognise pasted text wrapped in bracket paste sequences, rather
than only forwarding them to the program inside.
* Have client return 1 if process is interrupted to an input pane.
* Query the client terminal for foreground and background colours and if OSC 10
or 11 is received but no colour has been set inside tmux, return the colour
from the first attached client.
* Add send-keys -K to handle keys directly as if typed (so look up in key
table).
* Process escape sequences in show-buffer.
* Add a -l flag to display-message to disable format expansion.
* Add paste-buffer-deleted notification and fix name of paste-buffer-changed.
* Do not attempt to connect to the socket as a client if systemd is active.
* Add scroll-top and scroll-bottom commands to scroll so cursor is at top or
bottom.
* Add a -T flag to capture-pane to stop at the last used cell instead of the
full width. Restore the previous behaviour by making it default to off unless
-J is used.
* Add message-line option to control where message and prompt go.
* Notification when a paste buffer is deleted.
* Add a Nobr terminfo(5) capability to tell tmux the terminal does not use bright
colours for bold.
* Change g and G to go to top and bottom in menus.
* Add a third state "all" to allow-passthrough to work even in invisible panes.
* Add support for OSC 8 hyperlinks.
* Store the time lines are scrolled into history and display in copy mode.
* Add a %config-error reply to control mode for configuration file errors since
reporting them in view mode is useless.
* A new feature flag (ignorefkeys) to ignore terminfo(5) function key
definitions for rxvt.
* Pass through first argument to OSC 52 (which clipboards to set) if the
application provides it.
* Expand arguments to send-keys, capture-pane, split-window, join-pane where it
makes sense to do so.
* Ignore named buffers when choosing a buffer if one is not specified by the user.
CHANGES FROM 3.3 TO 3.3a
* Do not crash when run-shell produces output from a config file.
* Do not unintentionally turn off all mouse mode when button mode is also
present.
CHANGES FROM 3.2a TO 3.3
* Add an ACL list for users connecting to the tmux socket. Users may be
forbidden from attaching, forced to attach read-only, or allowed to attach
read-write. A new command, server-access, configures the list. File system
permissions must still be configured manually.
* Emit window-layout-changed on swap-pane.
* Better error reporting when applying custom layouts.
* Handle ANSI escape sequences in run-shell output.
* Add pane_start_path to match start_command.
* Set PWD so shells have a hint about the real path.
* Do not allow pipe-pane on dead panes.
* Do not report mouse positions (incorrectly) above the maximum of 223 in
normal mouse mode.
* Add an option (default off) to control the passthrough escape sequence.
* Support more mouse buttons when the terminal sends them.
* Add a window-resized hook which is fired when the window is actually resized
which may be later than the client resize.
* Add next_session_id format with the next session ID.
* Add formats for client and server UID and user.
* Add argument to refresh-client -l to forward clipboard to a pane.
* Add remain-on-exit-format to set text shown when pane is dead.
* With split-window -f use percentages of window size not pane size.
* Add an option (fill-character) to set the character used for unused areas of
a client.
* Add an option (scroll-on-clear) to control if tmux scrolls into history on
clear.
* Add a capability for OSC 7 and use it similarly to how the title is set (and
controlled by the same set-titles option).
* Add support for systemd socket activation (where systemd creates the Unix
domain socket for tmux rather than tmux creating it). Build with
--enable-systemd.
* Add an option (pane-border-indicators) to select how the active pane is shown
on the pane border (colour, arrows or both).
* Support underscore styles with capture-pane -e.
* Make pane-border-format a pane option rather than window.
* Respond to OSC 4 queries
* Fix g/G keys in modes to do the same thing as copy mode (and vi).
* Bump the time terminals have to respond to device attributes queries to three
seconds.
* If automatic-rename is off, allow the rename escape sequence to set an empty
name.
* Trim menu item text more intelligently.
* Add cursor-style and cursor-colour options to set the default cursor style
and colour.
* Accept some useful and non-conflicting emacs keys in vi normal mode at the
command prompt.
* Add a format modifier (c) to force a colour to RGB.
* Add -s and -S to display-popup to set styles, -b to set lines and -T to set
popup title. New popup-border-lines, popup-border-style and popup-style
options set the defaults.
* Add -e flag to set an environment variable for a popup.
* Make send-keys without arguments send the key it is bound to (if bound to a
key).
* Try to leave terminal cursor at the right position even when tmux is drawing
its own cursor or selection (such as at the command prompt and in choose
mode) for people using screen readers and similar which can make use of it.
* Change so that {} is converted to tmux commands immediately when parsed. This
means it must contain valid tmux commands. For commands which expand %% and
%%%, this now only happens within string arguments. Use of nested aliases
inside {} is now forbidden. Processing of commands given in quotes remains
the same.
* Disable evports on SunOS since they are broken.
* Do not expand the file given with tmux -f so it can contain :s.
* Bump FORMAT_LOOP_LIMIT and add a log message when hit.
* Add a terminal feature for the mouse (since FreeBSD termcap does not have kmous).
* Forbid empty session names.
* Improve error reporting when the tmux /tmp directory cannot be created or
used.
* Give #() commands a one second grace period where the output is empty before
telling the user they aren't doing anything ("not ready").
* When building, pick default-terminal from the first of tmux-256color, tmux,
screen-256color, screen that is available on the build system (--with-TERM
can override).
* Do not close popups on resize, instead adjust them to fit.
* Add a client-active hook.
* Make window-linked and window-unlinked window options.
* Do not configure on macOS without the user making a choice about utf8proc
(either --enable-utf8proc or --disable-utf8proc).
* Do not freeze output in panes when a popup is open, let them continue to
redraw.
* Add pipe variants of the line copy commands.
* Change copy-line and copy-end-of-line not to cancel and add -and-cancel
variants, like the other copy commands.
* Support the OSC palette-setting sequences in popups.
* Add a pane-colours array option to specify the defaults palette.
* Add support for Unicode zero-width joiner.
* Make newline a style delimiter as well so they can cross multiple lines for
readability in configuration files.
* Change focus to be driven by events rather than scanning panes so the
ordering of in and out is consistent.
* Add display-popup -B to open a popup without a border.
* Add a menu for popups that can be opened with button three outside the popup
or on the left or top border. Resizing now only works on the right and bottom
borders or when using Meta. The menu allows a popup to be closed, expanded to
the full size of the client, centered in the client or changed into a pane.
* Make command-prompt and confirm-before block by default (like run-shell). A
new -b flags runs them in the background as before. Also set return code for
confirm-before.
* Change cursor style handling so tmux understands which sequences contain
blinking and sets the flag appropriately, means that it works whether cnorm
disables blinking or not. This now matches xterm's behaviour.
* More accurate vi(1) word navigation in copy mode and on the status line. This
changes the meaning of the word-separators option: setting it to the empty
string is equivalent to the previous behavior.
* Add -F for command-prompt and use it to fix "Rename" on the window menu.
* Add different command histories for different types of prompts ("command",
"search" etc).
CHANGES FROM 3.2 TO 3.2a
* Add an "always" value for the "extended-keys" option; if set then tmux will
forward extended keys to applications even if they do not request them.
* Add a "mouse" terminal feature so tmux can enable the mouse on terminals
where it is known to be supported even if terminfo(5) says otherwise.
* Do not expand the filename given to -f so it can contain colons.
* Fixes for problems with extended keys and modifiers, scroll region,
source-file, cross compiling, format modifiers and other minor issues.
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.
* Add 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-active-border-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 replies 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 are 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
be used 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
* Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments.
CHANGES FROM 3.1a TO 3.1b
* Fix build on systems without sys/queue.h.
* Fix crash when allow-rename is on and an empty name is set.
CHANGES FROM 3.1 TO 3.1a
* Do not close stdout prematurely in control mode since it is needed to print
exit messages. Prevents hanging when detaching with iTerm2.
CHANGES FROM 3.0a TO 3.1
* Only search the visible part of the history when marking (highlighting)
search terms. This is much faster than searching the whole history and solves
problems with large histories. The count of matches shown is now the visible
matches rather than all matches.
* Search using regular expressions in copy mode. search-forward and
search-backward use regular expressions by default; the incremental versions
do not.
* Turn off mouse mode 1003 as well as the rest when exiting.
* Add selection_active format for when the selection is present but not moving
with the cursor.
* Fix dragging with modifier keys, so binding keys such as C-MouseDrag1Pane and
C-MouseDragEnd1Pane now work.
* Add -a to list-keys to also list keys without notes with -N.
* Do not jump to next word end if already on a word end when selecting a word;
fixes select-word with single character words and vi(1) keys.
* Fix top and bottom pane calculation with pane border status enabled.
* Add support for adding a note to a key binding (with bind-key -N) and use
this to add descriptions to the default key bindings. A new -N flag to
list-keys shows key bindings with notes. Change the default ? binding to use
this to show a readable summary of keys. Also extend command-prompt to return
the name of the key pressed and add a default binding (/) to show the note
for the next key pressed.
* Add support for the iTerm2 DSR 1337 sequence to get the terminal version.
* Treat plausible but invalid keys (like C-BSpace) as literal like any other
unrecognised string passed to send-keys.
* Detect iTerm2 and enable use of DECSLRM (much faster with horizontally split
windows).
* Add -Z to default switch-client command in tree mode.
* Add ~ to quoted characters for %%%.
* Document client exit messages in the manual page.
* Do not let read-only clients limit the size, unless all clients are
read-only.
* Add a number of new formats to inspect what sessions and clients a window is
present or active in.
* Change file reading and writing to go through the client if necessary. This
fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
support "-" for standard input, like load-buffer and save-buffer.
* Add ~/.config/tmux/tmux.conf to the default search path for configuration
files.
* Bump the escape sequence timeout to five seconds to allow for longer
legitimate sequences.
* Make a best effort to set xpixel and ypixel for each pane and add formats for
them.
* Add push-default to status-left and status-right in status-format[0].
* Do not clear search marks on cursor movement with vi(1) keys.
* Add p format modifier for padding to width and allow multiple substitutions
in a single format.
* Add -f for full size to join-pane (like split-window).
* Do not use bright when emulating 256 colours on an 8 colour terminal because
it is also bold on some terminals.
* Make select-pane -P set window-active-style also to match previous behaviour.
* Do not truncate list-keys output.
* Turn automatic-rename back on if the \033k rename escape sequence is used
with an empty name.
* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
split-window and join-pane -l to accept similar percentages and deprecate the
-p flag.
* Add -F flag to send-keys to expand formats in search-backward and forward
copy mode commands and copy_cursor_word and copy_cursor_line formats for word
and line at cursor in copy mode. Use for default # and * binding with vi(1)
keys.
* Add formats for word and line at cursor position in copy mode.
* Add formats for cursor and selection position in copy mode.
* Support all the forms of RGB colour strings in OSC sequences rather than
requiring two digits.
* Limit lazy resize to panes in attached sessions only.
* Add an option to set the key sent by backspace for those whose system uses ^H
rather than ^?.
* Change new-session -A without a session name (that is, no -s option also) to
attach to the best existing session like attach-session rather than a new
one.
* Add a "latest" window-size option which tries to size windows based on the
most recently used client. This is now the default.
* Add simple support for OSC 7 (result is available in the pane_path format).
* Add push-default and pop-default for styles which change the colours and
attributes used for #[default]. These are used in status-format to restore
the behaviour of window-status-style being the default for
window-status-format.
* Add window_marked_flag.
* Add cursor-down-and-cancel in copy mode.
* Default to previous search string for search-forward and search-backward.
* Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
preserve zoomed state.
* Add -N to capture-pane to preserve trailing spaces.
* Add reverse sorting in tree, client and buffer modes.
CHANGES FROM 3.0 TO 3.0a
CHANGES FROM 3.0 to 3.0a
* Do not require REG_STARTEND.
@ -924,7 +12,7 @@ CHANGES FROM 3.0 TO 3.0a
* Do not crash when restoring a layout with only one pane.
CHANGES FROM 2.9 TO 3.0
CHANGES FROM 2.9 to 3.0
* Workaround invalid layout strings generated by older tmux versions and add
some additional sanity checks
@ -1014,7 +102,7 @@ CHANGES FROM 2.9 TO 3.0
* Add the ability to create simple menus. Introduces new command
display-menu. Default menus are bound to MouseDown3 on the status line;
MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
buffer modes; and C-b < and >.
buffer modes; and C-b C-m and C-b M-m.
* Allow panes to be empty (no command). They can be created either by piping to
split-window -I, or by passing an empty command ('') to split-window. Output
@ -1049,11 +137,11 @@ CHANGES FROM 2.9 TO 3.0
* Add the ability to infer an option type (server, session, window) from its
name to show-options (it was already present in set-option).
CHANGES FROM 2.9 TO 2.9a
CHANGES FROM 2.9 to 2.9a
* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
CHANGES FROM 2.8 TO 2.9
CHANGES FROM 2.8 to 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
@ -1178,7 +266,7 @@ CHANGES FROM 2.8 TO 2.9
moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
CHANGES FROM 2.7 TO 2.8
CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it
times out.
@ -1504,7 +592,7 @@ Incompatible Changes
bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'"
There are also some new commands available with send -X, such as
There are also some new commmands available with send -X, such as
copy-pipe-and-cancel.
* set-remain-on-exit has gone -- can be achieved with hooks instead.
* Hooks: before hooks have been removed and only a selection of commands now
@ -3480,7 +2568,7 @@ The list of older changes is below.
* (nicm) -n on new-session is now -s, and -n is now the initial window name.
This was documented but not implemented :-/.
* (nicm) kill-window command, bound to & by default (because it should be hard
to hit accidentally).
to hit accidently).
* (nicm) bell-style option with three choices: "none" completely ignore bell;
"any" pass through a bell in any window to current; "current" ignore bells
except in current window. This applies only to the bell terminal signal,

View File

@ -1,19 +1,16 @@
# Makefile.am
# Obvious program stuff.
bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README README.ja COPYING example_tmux.conf \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1
dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ \
-DTMUX_VERSION='"@VERSION@"' \
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \
-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
-DTMUX_TERM='"@DEFAULT_TERM@"'
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
# Additional object files.
LDADD = $(LIBOBJS)
@ -28,10 +25,7 @@ AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
if IS_DARWIN
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined
endif
AM_CFLAGS += -Wno-unused-result
AM_CPPFLAGS += -DDEBUG
endif
AM_CPPFLAGS += -iquote.
@ -61,16 +55,6 @@ if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif
# Set flags for Haiku.
if IS_HAIKU
AM_CPPFLAGS += -D_BSD_SOURCE
endif
# Set flags for Cygwin.
if IS_CYGWIN
AM_CPPFLAGS += -DTMUX_SOCK_PERM=0
endif
# List of sources.
dist_tmux_SOURCES = \
alerts.c \
@ -127,14 +111,12 @@ dist_tmux_SOURCES = \
cmd-select-pane.c \
cmd-select-window.c \
cmd-send-keys.c \
cmd-server-access.c \
cmd-set-buffer.c \
cmd-set-environment.c \
cmd-set-option.c \
cmd-show-environment.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-show-prompt-history.c \
cmd-source-file.c \
cmd-split-window.c \
cmd-swap-pane.c \
@ -148,13 +130,10 @@ dist_tmux_SOURCES = \
control-notify.c \
control.c \
environ.c \
file.c \
format.c \
format-draw.c \
grid-reader.c \
grid-view.c \
grid.c \
hyperlinks.c \
input-keys.c \
input.c \
job.c \
@ -171,14 +150,12 @@ dist_tmux_SOURCES = \
options-table.c \
options.c \
paste.c \
popup.c \
proc.c \
regsub.c \
resize.c \
screen-redraw.c \
screen-write.c \
screen.c \
server-acl.c \
server-client.c \
server-fn.c \
server.c \
@ -188,23 +165,20 @@ dist_tmux_SOURCES = \
style.c \
tmux.c \
tmux.h \
tmux-protocol.h \
tty-acs.c \
tty-features.c \
tty-keys.c \
tty-term.c \
tty.c \
utf8-combined.c \
utf8.c \
window-buffer.c \
window-client.c \
window-clock.c \
window-copy.c \
window-customize.c \
window-tree.c \
window.c \
xmalloc.c \
xmalloc.h
xmalloc.h \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty.
@ -212,27 +186,11 @@ if NEED_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
# Add compat file for systemd.
if HAVE_SYSTEMD
nodist_tmux_SOURCES += compat/systemd.c
endif
# Add compat file for utf8proc.
if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
# Enable sixel support.
if ENABLE_SIXEL
dist_tmux_SOURCES += image.c image-sixel.c
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-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \

16
README
View File

@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
* Dependencies
@ -16,9 +16,6 @@ It also depends on ncurses, available from:
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
To build and install tmux from a release tarball, use:
@ -36,7 +33,6 @@ autoconf, automake and pkg-config:
$ cd tmux
$ sh autogen.sh
$ ./configure && make
$ sudo make install
* Contributing
@ -56,17 +52,9 @@ source tree with:
A small example configuration is in example_tmux.conf.
Other documentation is available in the wiki:
https://github.com/tmux/tmux/wiki
Also see the tmux FAQ at:
https://github.com/tmux/tmux/wiki/FAQ
A bash(1) completion file is at:
https://github.com/scop/bash-completion/blob/main/completions/tmux
https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with -v and -vv to generate server and client log files
in the current directory.

View File

@ -3,7 +3,7 @@ tmuxへようこそ!
tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
OpenBSD、FreeBSD、NetBSD、Linux、macOS、Solarisで実行できます。
OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。
tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。
@ -38,7 +38,7 @@ tmuxのドキュメントについてはtmux.1マニュアルをご覧くださ
サンプル設定は本リポジトリのexample_tmux.confに
また、bash-completionファイルは下記にあります。
https://github.com/scop/bash-completion/blob/main/completions/tmux
https://github.com/imomaliev/tmux-bash-completion
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。

34
SYNCING
View File

@ -1,17 +1,17 @@
Preamble
========
Tmux portable relies on repositories "tmux" and "tmux-obsd".
Tmux portable relies on repositories "tmux" and "tmux-openbsd".
Here's a description of them:
* "tmux" is the portable version, the one which contains code for other
operating systems, and autotools, etc., which isn't found or needed in the
OpenBSD base system.
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
the basis of the portable tmux version.
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the
@ -34,11 +34,11 @@ this information has ever been set before.
Cloning repositories
====================
This involves having both tmux and tmux-obsd cloned, as in:
This involves having both tmux and tmux-openbsd cloned, as in:
% cd /some/where/useful
% git clone https://github.com/tmux/tmux.git
% git clone https://github.com/ThomasAdam/tmux-obsd.git
% git clone https://github.com/ThomasAdam/tmux-openbsd.git
Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have
@ -47,30 +47,30 @@ these checkouts existing, skip that.
Adding in git-remotes
=====================
Because the portable "tmux" git repository and the "tmux-obsd"
Because the portable "tmux" git repository and the "tmux-openbsd"
repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and
"tmux-obsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-obsd" repository from the "tmux" repository, as
"tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-openbsd" repository from the "tmux" repository, as
shown by the following command:
% cd /path/to/tmux
% git remote add obsd-tmux file:///path/to/tmux-obsd
% git remote add obsd-tmux file:///path/to/tmux-openbsd
So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-obsd" repository, but from the context of the
commits from the "tmux-openbsd" repository, but from the context of the
portable "tmux" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them.
Fetching updates
================
To ensure the latest commits from "tmux-obsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
up-to-date first, and then reference that update in "tmux", as in:
% cd /path/to/tmux-obsd
% cd /path/to/tmux-openbsd
% git checkout master
% git pull
@ -82,17 +82,17 @@ Then back in "tmux":
Creating the necessary branches
===============================
Now that "tmux" can see commits and branches from "tmux-obsd" by way
Now that "tmux" can see commits and branches from "tmux-openbsd" by way
of the remote name "obsd-tmux", we can now create the master branch from
"tmux-obsd" in the "tmux" repository:
"tmux-openbsd" in the "tmux" repository:
% git checkout -b obsd-master obsd-tmux/master
Adding in the fake history points
=================================
=================================
To tie both the "master" branch from "tmux" and the "obsd-master"
branch from "tmux-obsd" together, the fake history points added to the
branch from "tmux-openbsd" together, the fake history points added to the
"tmux" repository need to be added. To do this, we must add an
additional refspec line, as in:

View File

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

File diff suppressed because it is too large Load Diff

View File

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

129
cfg.c
View File

@ -27,15 +27,12 @@
#include "tmux.h"
struct client *cfg_client;
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
static struct cmdq_item *cfg_item;
int cfg_quiet = 1;
char **cfg_files;
u_int cfg_nfiles;
static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{
@ -51,7 +48,8 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
cfg_show_causes(NULL);
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL)
cmdq_continue(cfg_item);
@ -61,12 +59,19 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
return (CMD_RETURN_NORMAL);
}
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
void
start_cfg(void)
{
struct client *c;
u_int i;
int flags = 0;
const char *home;
int flags = 0;
struct client *c;
/*
* Configuration files are loaded without a client, so commands are run
@ -84,23 +89,27 @@ start_cfg(void)
cmdq_append(c, cfg_item);
}
if (cfg_quiet)
if (cfg_file == NULL)
load_cfg(TMUX_CONF, c, NULL, CMD_PARSE_QUIET, NULL);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
flags = CMD_PARSE_QUIET;
for (i = 0; i < cfg_nfiles; i++)
load_cfg(cfg_files[i], c, NULL, NULL, flags, NULL);
}
if (cfg_file != NULL)
load_cfg(cfg_file, c, NULL, flags, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
int
load_cfg(const char *path, struct client *c, struct cmdq_item *item,
struct cmd_find_state *current, int flags, struct cmdq_item **new_item)
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmdq_item **new_item)
{
FILE *f;
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
@ -122,6 +131,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
pr = cmd_parse_from_file(f, &pi);
fclose(f);
if (pr->status == CMD_PARSE_EMPTY)
return (0);
if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error);
free(pr->error);
@ -132,71 +143,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
return (0);
}
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
state = cmdq_copy_state(cmdq_get_state(item), current);
cmdq_insert_after(item, new_item0);
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)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
return (0);
}
int
load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct client *c, struct cmdq_item *item, struct cmd_find_state *current,
int flags, struct cmdq_item **new_item)
{
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
log_debug("loading %s", path);
memset(&pi, 0, sizeof pi);
pi.flags = flags;
pi.file = path;
pi.line = 1;
pi.item = item;
pi.c = c;
pr = cmd_parse_from_buffer(buf, len, &pi);
if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error);
free(pr->error);
return (-1);
}
if (flags & CMD_PARSE_PARSEONLY) {
cmd_list_free(pr->cmdlist);
return (0);
}
if (item != NULL)
state = cmdq_copy_state(cmdq_get_state(item), current);
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)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
@ -236,41 +188,22 @@ cfg_print_causes(struct cmdq_item *item)
void
cfg_show_causes(struct session *s)
{
struct client *c = TAILQ_FIRST(&clients);
struct window_pane *wp;
struct window_mode_entry *wme;
u_int i;
if (cfg_ncauses == 0)
return;
if (c != NULL && (c->flags & CLIENT_CONTROL)) {
for (i = 0; i < cfg_ncauses; i++) {
control_write(c, "%%config-error %s", cfg_causes[i]);
free(cfg_causes[i]);
}
goto out;
}
if (s == NULL) {
if (c != NULL && c->session != NULL)
s = c->session;
else
s = RB_MIN(sessions, &sessions);
}
if (s == NULL || s->attached == 0) /* wait for an attached session */
if (s == NULL || cfg_ncauses == 0)
return;
wp = s->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
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++) {
window_copy_add(wp, 0, "%s", cfg_causes[i]);
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);
}
out:
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;

386
client.c
View File

@ -18,12 +18,12 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
@ -34,8 +34,8 @@
static struct tmuxproc *client_proc;
static struct tmuxpeer *client_peer;
static uint64_t client_flags;
static int client_suspended;
static int client_flags;
static struct event client_stdin;
static enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
@ -45,24 +45,20 @@ static enum {
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag;
static int client_exitval;
static enum msgtype client_exittype;
static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell;
static const char *client_execcmd;
static int client_attached;
static struct client_files client_files = RB_INITIALIZER(&client_files);
static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *,
uint64_t);
static void client_send_identify(const char *, const char *,
char **, u_int, const char *, int);
static int client_connect(struct event_base *, const char *, int);
static void client_send_identify(const char *, const char *);
static void client_stdin_callback(int, short, void *);
static void client_write(int, const char *, size_t);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
@ -102,7 +98,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */
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;
size_t size;
@ -127,9 +123,7 @@ retry:
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
if (flags & CLIENT_NOSTARTSERVER)
goto failed;
if (~flags & CLIENT_STARTSERVER)
if (!start_server)
goto failed;
close(fd);
@ -161,7 +155,7 @@ retry:
close(lockfd);
return (-1);
}
fd = server_start(client_proc, flags, base, lockfd, lockfile);
fd = server_start(client_proc, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@ -213,81 +207,63 @@ client_exit_message(void)
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
}
return ("unknown reason");
}
/* Exit if all streams flushed. */
static void
client_exit(void)
{
if (!file_write_left(&client_files))
proc_exit(client_proc);
}
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
int feat)
client_main(struct event_base *base, int argc, char **argv, int flags)
{
struct cmd_parse_result *pr;
struct msg_command *data;
int fd, i;
const char *ttynam, *termname, *cwd;
struct cmd *cmd;
struct msg_command_data *data;
int cmdflags, fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
struct termios tio, saved_tio;
size_t size, linesize = 0;
ssize_t linelen;
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
struct args_value *values;
size_t size;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */
cmdflags = 0;
if (shell_command != NULL) {
msg = MSG_SHELL;
flags |= CLIENT_STARTSERVER;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
flags |= CLIENT_STARTSERVER;
cmdflags = CMD_STARTSERVER;
} else {
msg = MSG_COMMAND;
/*
* It's annoying parsing the command string twice (in client
* and later in server) but it is necessary to get the start
* server flag.
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
values = args_from_vector(argc, argv);
pr = cmd_parse_from_arguments(values, argc, NULL);
pr = cmd_parse_from_arguments(argc, argv, NULL);
if (pr->status == CMD_PARSE_SUCCESS) {
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
flags |= CLIENT_STARTSERVER;
TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
args_free_values(values, argc);
free(values);
}
/* Create client process structure (starts logging). */
client_proc = proc_start("client");
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. */
#ifdef HAVE_SYSTEMD
if (systemd_activated()) {
/* socket-based activation, do not even try to be a client. */
fd = server_start(client_proc, flags, base, 0, NULL);
} else
#endif
fd = client_connect(base, socket_path, client_flags);
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
@ -305,8 +281,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
if ((termname = getenv("TERM")) == NULL)
termname = "";
/*
* Drop privileges for client. "proc exec" is needed for -c and for
@ -317,21 +291,9 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
*
* "sendfd" is dropped later in client_dispatch_wait().
*/
if (pledge(
"stdio rpath wpath cpath unix sendfd proc exec tty",
NULL) != 0)
if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
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. */
if (ptm_fd != -1)
close(ptm_fd);
@ -340,7 +302,10 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
options_free(global_w_options);
environ_free(global_environ);
/* Set up control mode. */
/* Create stdin handler. */
setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL);
if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
fprintf(stderr, "tcgetattr failed: %s\n",
@ -362,9 +327,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
}
/* Send identify messages. */
client_send_identify(ttynam, termname, caps, ncaps, cwd, feat);
tty_term_free_list(caps, ncaps);
proc_flush_peer(client_peer);
client_send_identify(ttynam, cwd);
/* Send first command. */
if (msg == MSG_COMMAND) {
@ -407,11 +370,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
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. */
if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE)
@ -420,66 +378,42 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROL) {
} else if (client_flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message());
else
printf("%%exit\n");
fflush(stdout);
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
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);
}
printf("\033\\");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
} else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
/* Send identify messages to server. */
static void
client_send_identify(const char *ttynam, const char *termname, char **caps,
u_int ncaps, const char *cwd, int feat)
client_send_identify(const char *ttynam, const char *cwd)
{
char **ss;
size_t sslen;
int fd;
uint64_t flags = client_flags;
pid_t pid;
u_int i;
const char *s;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags);
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
strlen(termname) + 1);
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 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)
fatal("dup failed");
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();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
@ -494,14 +428,59 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
}
/* Callback for client stdin read events. */
static void
client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg)
{
struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size == -1 && (errno == EINTR || errno == EAGAIN))
return;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
if (data.size <= 0)
event_del(&client_stdin);
}
/* Force write to file descriptor. */
static void
client_write(int fd, const char *data, size_t size)
{
ssize_t used;
log_debug("%s: %.*s", __func__, (int)size, data);
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
break;
}
data += used;
size -= used;
}
}
/* Run command in shell; used for -c. */
static __dead void
client_exec(const char *shell, const char *shellcmd)
{
char *argv0;
const char *name, *ptr;
char *argv0;
log_debug("shell %s, command %s", shell, shellcmd);
argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
name = ptr + 1;
else
name = shell;
if (client_flags & CLIENT_LOGIN)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1);
@ -521,23 +500,11 @@ client_signal(int sig)
{
struct sigaction sigact;
int status;
pid_t pid;
log_debug("%s: %s", __func__, strsignal(sig));
if (sig == SIGCHLD) {
for (;;) {
pid = waitpid(WAIT_ANY, &status, WNOHANG);
if (pid == 0)
break;
if (pid == -1) {
if (errno == ECHILD)
break;
log_debug("waitpid failed: %s",
strerror(errno));
}
}
} else if (!client_attached) {
if (sig == SIGTERM || sig == SIGHUP)
if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) {
if (sig == SIGTERM)
proc_exit(client_proc);
} else {
switch (sig) {
@ -547,8 +514,7 @@ client_signal(int sig)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case SIGTERM:
if (!client_suspended)
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
@ -563,31 +529,18 @@ client_signal(int sig)
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
client_suspended = 0;
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. */
static void
client_dispatch(struct imsg *imsg, __unused void *arg)
{
if (imsg == NULL) {
if (!client_exitflag) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
}
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
proc_exit(client_proc);
return;
}
@ -598,39 +551,16 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
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). */
static void
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
static int pledge_applied;
char *data;
ssize_t datalen;
struct msg_stdout_data stdoutdata;
struct msg_stderr_data stderrdata;
int retval;
static int pledge_applied;
/*
* "sendfd" is no longer required once all of the identify messages
@ -639,12 +569,10 @@ client_dispatch_wait(struct imsg *imsg)
* get the first message from the server.
*/
if (!pledge_applied) {
if (pledge(
"stdio rpath wpath cpath unix proc exec tty",
NULL) != 0)
if (pledge("stdio unix proc exec tty", NULL) != 0)
fatal("pledge failed");
pledge_applied = 1;
}
};
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
@ -652,17 +580,44 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
client_dispatch_exit_message(data, datalen);
client_exitflag = 1;
client_exit();
if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
proc_exit(client_proc);
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_del(&client_stdin);
client_attached = 1;
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
fatalx("bad MSG_STDIN size");
event_add(&client_stdin, NULL);
break;
case MSG_STDOUT:
if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break;
case MSG_STDERR:
if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, data, sizeof stderrdata);
client_write(STDERR_FILENO, stderrdata.data,
stderrdata.size);
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
@ -673,14 +628,6 @@ client_dispatch_wait(struct imsg *imsg)
client_exitval = 1;
proc_exit(client_proc);
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:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
@ -694,31 +641,6 @@ client_dispatch_wait(struct imsg *imsg)
case MSG_EXITED:
proc_exit(client_proc);
break;
case MSG_READ_OPEN:
file_read_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
case MSG_READ_CANCEL:
file_read_cancel(&client_files, imsg);
break;
case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
case MSG_WRITE:
file_write_data(&client_files, imsg);
break;
case MSG_WRITE_CLOSE:
file_write_close(&client_files, imsg);
break;
case MSG_OLDSTDERR:
case MSG_OLDSTDIN:
case MSG_OLDSTDOUT:
fprintf(stderr, "server version is too old for client\n");
proc_exit(client_proc);
break;
}
}
@ -734,14 +656,6 @@ client_dispatch_attached(struct imsg *imsg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
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_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0')
@ -766,10 +680,11 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT:
client_dispatch_exit_message(data, datalen);
if (client_exitreason == CLIENT_EXIT_NONE)
client_exitreason = CLIENT_EXIT_EXITED;
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break;
case MSG_EXITED:
if (datalen != 0)
@ -795,7 +710,6 @@ client_dispatch_attached(struct imsg *imsg)
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_suspended = 1;
kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:

View File

@ -37,29 +37,27 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
.args = { "c:dEf:rt:x", 0, 0, NULL },
.usage = "[-dErx] [-c working-directory] [-f flags] "
CMD_TARGET_SESSION_USAGE,
.args = { "c:dErt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
/* -t is special */
.flags = CMD_STARTSERVER|CMD_READONLY,
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
};
enum cmd_retval
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 target;
struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
int flags;
struct client *c = cmdq_get_client(item), *c_loop;
struct client *c = item->client, *c_loop;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
char *cwd, *cause;
char *cause;
enum msgtype msgtype;
if (RB_EMPTY(&sessions)) {
@ -69,7 +67,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (c == NULL)
return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
@ -83,11 +80,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
type = CMD_FIND_SESSION;
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);
s = target.s;
wl = target.wl;
wp = target.wp;
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (wl != NULL) {
if (wp != NULL)
@ -100,14 +97,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
}
if (cflag != NULL) {
cwd = format_single(item, cflag, c, s, wl, wp);
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;
if (c->session != NULL) {
@ -125,15 +117,24 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag || xflag) {
if (xflag)
@ -149,17 +150,24 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
server_client_set_session(c, s);
c->session = s;
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED;
}
if (cfg_finished)
cfg_show_causes(s);
recalculate_sizes();
alerts_check_session(s);
server_update_socket();
return (CMD_RETURN_NORMAL);
}
@ -167,9 +175,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
static enum cmd_retval
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'),
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

@ -27,44 +27,33 @@
* Bind a key to a command.
*/
static enum args_parse_type cmd_bind_key_args_parse(struct args *, u_int,
char **);
static enum cmd_retval cmd_bind_key_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
.usage = "[-nr] [-T key-table] [-N note] key "
"[command [argument ...]]",
.args = { "cnrT:", 2, -1 },
.usage = "[-cnr] [-T key-table] key "
"command [arguments]",
.flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec
};
static enum args_parse_type
cmd_bind_key_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval
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;
const char *tablename, *note = args_get(args, 'N');
const char *tablename;
struct cmd_parse_result *pr;
int repeat;
struct args_value *value;
u_int count = args_count(args);
char **argv = args->argv;
int argc = args->argc;
key = key_string_lookup_string(args_string(args, 0));
key = key_string_lookup_string(argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args_string(args, 0));
cmdq_error(item, "unknown key: %s", argv[0]);
return (CMD_RETURN_ERROR);
}
@ -74,27 +63,15 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
tablename = "root";
else
tablename = "prefix";
repeat = args_has(args, 'r');
if (count == 1) {
key_bindings_add(tablename, key, note, repeat, NULL);
return (CMD_RETURN_NORMAL);
}
value = args_value(args, 1);
if (count == 2 && value->type == ARGS_COMMANDS) {
key_bindings_add(tablename, key, note, repeat, value->cmdlist);
value->cmdlist->references++;
return (CMD_RETURN_NORMAL);
}
if (count == 2)
pr = cmd_parse_from_string(args_string(args, 1), NULL);
else {
pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1,
NULL);
}
if (argc == 2)
pr = cmd_parse_from_string(argv[1], NULL);
else
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
cmdq_error(item, "empty command");
return (CMD_RETURN_ERROR);
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
@ -102,6 +79,6 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
case CMD_PARSE_SUCCESS:
break;
}
key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
key_bindings_add(tablename, key, args_has(args, 'r'), pr->cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@ -34,8 +34,8 @@ const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane",
.alias = "breakp",
.args = { "abdPF:n:s:t:", 0, 0, NULL },
.usage = "[-abdP] [-F format] [-n window-name] [-s src-pane] "
.args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 },
@ -48,61 +48,39 @@ const struct cmd_entry cmd_break_pane_entry = {
static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct client *tc = cmdq_get_target_client(item);
struct winlink *wl = source->wl;
struct session *src_s = source->s;
struct session *dst_s = target->s;
struct window_pane *wp = source->wp;
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->source.wl;
struct session *src_s = item->source.s;
struct session *dst_s = item->target.s;
struct window_pane *wp = item->source.wp;
struct window *w = wl->window;
char *name, *cause, *cp;
int idx = target->idx, before;
char *name, *cause;
int idx = item->target.idx;
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) {
cmdq_error(item, "index in use: %d", idx);
cmdq_error(item, "index %d already in use", idx);
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);
server_client_remove_pane(wp);
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
w = wp->window = window_create(w->sx, w->sy);
options_set_parent(wp->options, w->options);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->latest = tc;
if (!args_has(args, 'n')) {
name = default_window_name(w);
@ -115,12 +93,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_init(w, wp);
wp->flags |= PANE_CHANGED;
colour_palette_from_option(&wp->palette, wp->options);
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
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);
cmd_find_from_session(current, dst_s, 0);
}
@ -135,7 +112,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
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);
free(cp);
}

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -53,8 +53,8 @@ const struct cmd_entry cmd_clear_history_entry = {
.name = "clear-history",
.alias = "clearhist",
.args = { "Ht:", 0, 0, NULL },
.usage = "[-H] " CMD_TARGET_PANE_USAGE,
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t linelen;
u_int i;
pending = input_pending(wp->ictx);
pending = input_pending(wp);
if (pending == NULL)
return (xstrdup(""));
@ -107,20 +107,18 @@ static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len)
{
struct grid *gd;
const struct grid_line *gl;
struct screen *s;
struct grid_cell *gc = NULL;
struct window_mode_entry *wme;
int n, join_lines, flags = 0;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
int n, with_codes, escape_c0, join_lines;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
gd = wp->base.saved_grid;
gd = wp->saved_grid;
if (gd == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen");
@ -128,27 +126,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
}
return (xstrdup(""));
}
s = &wp->base;
} else if (args_has(args, 'M')) {
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->get_screen != NULL) {
s = wme->mode->get_screen (wme);
gd = s->grid;
} else {
s = &wp->base;
gd = wp->base.grid;
}
} else {
s = &wp->base;
} else
gd = wp->base.grid;
}
Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
top = 0;
else {
n = args_strtonum_and_expand(args, 'S', INT_MIN, SHRT_MAX,
item, &cause);
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
free(cause);
@ -164,8 +149,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
if (Eflag != NULL && strcmp(Eflag, "-") == 0)
bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum_and_expand(args, 'E', INT_MIN, SHRT_MAX,
item, &cause);
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
@ -183,19 +167,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
top = tmp;
}
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
if (args_has(args, 'e'))
flags |= GRID_STRING_WITH_SEQUENCES;
if (args_has(args, 'C'))
flags |= GRID_STRING_ESCAPE_SEQUENCES;
if (!join_lines && !args_has(args, 'T'))
flags |= GRID_STRING_EMPTY_CELLS;
if (!join_lines && !args_has(args, 'N'))
flags |= GRID_STRING_TRIM_SPACES;
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
escape_c0, !join_lines);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
@ -212,18 +191,16 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct window_pane *wp = cmdq_get_target(item)->wp;
struct args *args = self->args;
struct client *c;
struct window_pane *wp = item->target.wp;
char *buf, *cause;
const char *bufname;
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);
grid_clear_history(wp->base.grid);
if (args_has(args, 'H'))
screen_reset_hyperlinks(wp->screen);
return (CMD_RETURN_NORMAL);
}
@ -236,20 +213,18 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
if (len > 0 && buf[len - 1] == '\n')
len--;
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");
c = item->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(item, "can't write to stdout");
free(buf);
return (CMD_RETURN_ERROR);
}
evbuffer_add(c->stdout_data, buf, len);
free(buf);
if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
bufname = NULL;
if (args_has(args, 'b'))

View File

@ -24,18 +24,15 @@
* Enter a mode.
*/
static enum args_parse_type cmd_choose_tree_args_parse(struct args *args,
u_int idx, char **cause);
static enum cmd_retval cmd_choose_tree_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -47,9 +44,9 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -61,9 +58,9 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -71,47 +68,24 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:yZ", 0, 0, NULL },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
static enum args_parse_type
cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
struct args *args = self->args;
struct window_pane *wp = item->target.wp;
const struct window_mode *mode;
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
if (paste_is_empty())
if (self->entry == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
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)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry)
mode = &window_customize_mode;
else
} else
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);
}

View File

@ -29,10 +29,8 @@
* Prompt for command in client.
*/
static enum args_parse_type cmd_command_prompt_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static int cmd_command_prompt_callback(struct client *, void *,
const char *, int);
@ -42,112 +40,81 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
" [-T prompt-type] [template]",
.args = { "1iI:Np:t:", 0, 1 },
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.flags = CMD_CLIENT_TFLAG,
.flags = 0,
.exec = cmd_command_prompt_exec
};
struct cmd_command_prompt_prompt {
char *input;
char *prompt;
};
struct cmd_command_prompt_cdata {
struct cmdq_item *item;
struct args_command_state *state;
int flags;
int flags;
enum prompt_type prompt_type;
char *inputs;
char *next_input;
struct cmd_command_prompt_prompt *prompts;
u_int count;
u_int current;
char *prompts;
char *next_prompt;
int argc;
char **argv;
char *template;
int idx;
};
static enum args_parse_type
cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item);
const char *type, *s, *input;
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
char *tmp, *prompts, *prompt, *next_prompt;
char *inputs = NULL, *next_input;
u_int count = args_count(args);
int wait = !args_has(args, 'b'), space = 1;
struct client *c;
char *prompt, *ptr, *input = NULL;
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);
if (args_has(args, 'i'))
wait = 0;
cdata = xcalloc(1, sizeof *cdata);
if (wait)
cdata->item = item;
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
args_has(args, 'F'));
if ((s = args_get(args, 'p')) == NULL) {
if (count != 0) {
tmp = args_make_commands_get_command(cdata->state);
xasprintf(&prompts, "(%s)", tmp);
free(tmp);
} else {
prompts = xstrdup(":");
space = 0;
}
next_prompt = prompts;
} else
next_prompt = prompts = xstrdup(s);
if ((s = args_get(args, 'I')) != NULL)
next_input = inputs = xstrdup(s);
cdata->inputs = NULL;
cdata->next_input = NULL;
cdata->prompts = NULL;
cdata->next_prompt = NULL;
cdata->template = NULL;
cdata->idx = 1;
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
next_input = NULL;
while ((prompt = strsep(&next_prompt, ",")) != NULL) {
cdata->prompts = xreallocarray(cdata->prompts, cdata->count + 1,
sizeof *cdata->prompts);
if (!space)
tmp = xstrdup(prompt);
else
xasprintf(&tmp, "%s ", prompt);
cdata->prompts[cdata->count].prompt = tmp;
cdata->template = xstrdup("%1");
if (next_input != NULL) {
input = strsep(&next_input, ",");
if (input == NULL)
input = "";
} else
input = "";
cdata->prompts[cdata->count].input = xstrdup(input);
cdata->count++;
}
free(inputs);
free(prompts);
if ((type = args_get(args, 'T')) != NULL) {
cdata->prompt_type = status_prompt_type(type);
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "unknown type: %s", type);
cmd_command_prompt_free(cdata);
return (CMD_RETURN_ERROR);
}
if ((prompts = args_get(args, 'p')) != NULL)
cdata->prompts = xstrdup(prompts);
else if (args->argc != 0) {
n = strcspn(cdata->template, " ,");
xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template);
} else
cdata->prompt_type = PROMPT_TYPE_COMMAND;
cdata->prompts = xstrdup(":");
/* Get first prompt. */
cdata->next_prompt = cdata->prompts;
ptr = strsep(&cdata->next_prompt, ",");
if (prompts == NULL)
prompt = xstrdup(ptr);
else
xasprintf(&prompt, "%s ", ptr);
/* Get initial prompt input. */
if ((inputs = args_get(args, 'I')) != NULL) {
cdata->inputs = xstrdup(inputs);
cdata->next_input = cdata->inputs;
input = strsep(&cdata->next_input, ",");
}
if (args_has(args, '1'))
cdata->flags |= PROMPT_SINGLE;
@ -155,73 +122,69 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL;
else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY;
status_prompt_set(tc, target, cdata->prompts[0].prompt,
cdata->prompts[0].input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags);
free(prompt);
if (!wait)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
}
static int
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
struct cmd_command_prompt_cdata *cdata = data;
char *error;
struct cmdq_item *item = cdata->item, *new_item;
struct cmd_list *cmdlist;
struct cmd_command_prompt_prompt *prompt;
int argc = 0;
char **argv = NULL;
struct cmd_command_prompt_cdata *cdata = data;
struct cmdq_item *new_item;
char *new_template, *prompt, *ptr;
char *input = NULL;
struct cmd_parse_result *pr;
if (s == NULL)
goto out;
return (0);
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
if (done) {
if (cdata->flags & PROMPT_INCREMENTAL)
goto out;
cmd_append_argv(&cdata->argc, &cdata->argv, s);
if (++cdata->current != cdata->count) {
prompt = &cdata->prompts[cdata->current];
status_prompt_update(c, prompt->prompt, prompt->input);
return (1);
}
free(cdata->template);
cdata->template = new_template;
}
argc = cdata->argc;
argv = cmd_copy_argv(cdata->argc, cdata->argv);
if (!done)
cmd_append_argv(&argc, &argv, s);
/*
* Check if there are more prompts; if so, get its respective input
* and update the prompt data.
*/
if (done && (ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input);
if (done) {
cmd_free_argv(cdata->argc, cdata->argv);
cdata->argc = argc;
cdata->argv = cmd_copy_argv(argc, argv);
free(prompt);
cdata->idx++;
return (1);
}
cmdlist = args_make_commands(cdata->state, argc, argv, &error);
if (cmdlist == NULL) {
cmdq_append(c, cmdq_get_error(error));
free(error);
} else if (item == NULL) {
new_item = cmdq_get_command(cmdlist, NULL);
pr = cmd_parse_from_string(new_template, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, 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;
}
cmd_free_argv(argc, argv);
if (!done)
free(new_template);
if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1);
out:
if (item != NULL)
cmdq_continue(item);
return (0);
}
@ -229,14 +192,9 @@ static void
cmd_command_prompt_free(void *data)
{
struct cmd_command_prompt_cdata *cdata = data;
u_int i;
for (i = 0; i < cdata->count; i++) {
free(cdata->prompts[i].prompt);
free(cdata->prompts[i].input);
}
free(cdata->inputs);
free(cdata->prompts);
cmd_free_argv(cdata->argc, cdata->argv);
args_make_commands_free(cdata->state);
free(cdata->template);
free(cdata);
}

View File

@ -28,10 +28,8 @@
* Asks for confirmation before executing a command.
*/
static enum args_parse_type cmd_confirm_before_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static int cmd_confirm_before_callback(struct client *, void *,
const char *, int);
@ -41,80 +39,47 @@ const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before",
.alias = "confirm",
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
.usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
" command",
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.flags = CMD_CLIENT_TFLAG,
.flags = 0,
.exec = cmd_confirm_before_exec
};
struct cmd_confirm_before_data {
struct cmdq_item *item;
struct cmd_list *cmdlist;
u_char confirm_key;
int default_yes;
char *cmd;
};
static enum args_parse_type
cmd_confirm_before_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval
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 client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item);
char *new_prompt;
const char *confirm_key, *prompt, *cmd;
int wait = !args_has(args, 'b');
struct client *c;
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
cdata = xcalloc(1, sizeof *cdata);
cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
if (cdata->cmdlist == NULL) {
free(cdata);
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
}
if (wait)
cdata->item = item;
cdata->default_yes = args_has(args, 'y');
if ((confirm_key = args_get(args, 'c')) != NULL) {
if (confirm_key[1] == '\0' &&
confirm_key[0] > 31 &&
confirm_key[0] < 127)
cdata->confirm_key = confirm_key[0];
else {
cmdq_error(item, "invalid confirm key");
free(cdata);
return (CMD_RETURN_ERROR);
}
}
else
cdata->confirm_key = 'y';
if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt);
else {
cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd,
cdata->confirm_key);
ptr = copy = xstrdup(args->argv[0]);
cmd = strsep(&ptr, " \t");
xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
free(copy);
}
status_prompt_set(tc, target, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE, PROMPT_TYPE_COMMAND);
free(new_prompt);
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
if (!wait)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
free(new_prompt);
return (CMD_RETURN_NORMAL);
}
static int
@ -122,34 +87,34 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{
struct cmd_confirm_before_data *cdata = data;
struct cmdq_item *item = cdata->item, *new_item;
int retcode = 1;
struct cmdq_item *new_item;
struct cmd_parse_result *pr;
if (c->flags & CLIENT_DEAD)
goto out;
return (0);
if (s == NULL)
goto out;
if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes))
goto out;
retcode = 0;
if (s == NULL || *s == '\0')
return (0);
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0);
if (item == NULL) {
new_item = cmdq_get_command(cdata->cmdlist, NULL);
pr = cmd_parse_from_string(cdata->cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cdata->cmdlist,
cmdq_get_state(item));
cmdq_insert_after(item, 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;
}
out:
if (item != NULL) {
if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
return (0);
}
@ -158,6 +123,6 @@ cmd_confirm_before_free(void *data)
{
struct cmd_confirm_before_data *cdata = data;
cmd_list_free(cdata->cmdlist);
free(cdata->cmd);
free(cdata);
}

View File

@ -30,10 +30,9 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
.args = { "deHMqSs:t:u", 0, 0, NULL },
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
@ -44,7 +43,7 @@ const struct cmd_entry cmd_clock_mode_entry = {
.name = "clock-mode",
.alias = NULL,
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -56,48 +55,30 @@ const struct cmd_entry cmd_clock_mode_entry = {
static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct key_event *event = cmdq_get_event(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct client *c = item->client;
struct session *s;
struct window_pane *wp = target->wp, *swp;
if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp);
return (CMD_RETURN_NORMAL);
}
struct window_pane *wp = item->target.wp;
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);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
if (cmd_get_entry(self) == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL);
if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 's'))
swp = source->wp;
else
swp = wp;
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
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);
if (args_has(args, 'd'))
window_copy_pagedown(wp, 0, args_has(args, 'e'));
if (args_has(args, 'S')) {
window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y,
args_has(args, 'e'));
return (CMD_RETURN_NORMAL);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -33,13 +33,13 @@ const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client",
.alias = "detach",
.args = { "aE:s:t:P", 0, 0, NULL },
.args = { "aE:s:t:P", 0, 0 },
.usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY|CMD_CLIENT_TFLAG,
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
};
@ -47,25 +47,27 @@ const struct cmd_entry cmd_suspend_client_entry = {
.name = "suspend-client",
.alias = "suspendc",
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_CLIENT_TFLAG,
.flags = 0,
.exec = cmd_detach_client_exec
};
static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item);
struct client *tc = cmdq_get_target_client(item), *loop;
struct session *s;
enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
struct args *args = self->args;
struct client *c, *cloop;
struct session *s;
enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
if (cmd_get_entry(self) == &cmd_suspend_client_entry) {
server_client_suspend(tc);
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) {
server_client_suspend(c);
return (CMD_RETURN_NORMAL);
}
@ -75,35 +77,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
s = source->s;
s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session == s) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) {
if (cmd != NULL)
server_client_exec(loop, cmd);
server_client_exec(cloop, cmd);
else
server_client_detach(loop, msgtype);
server_client_detach(cloop, msgtype);
}
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL && loop != tc) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c) {
if (cmd != NULL)
server_client_exec(loop, cmd);
server_client_exec(cloop, cmd);
else
server_client_detach(loop, msgtype);
server_client_detach(cloop, msgtype);
}
}
return (CMD_RETURN_NORMAL);
}
if (cmd != NULL)
server_client_exec(tc, cmd);
server_client_exec(c, cmd);
else
server_client_detach(tc, msgtype);
server_client_detach(c, msgtype);
return (CMD_RETURN_STOP);
}

View File

@ -27,324 +27,75 @@
* Display a menu on a client.
*/
static enum args_parse_type cmd_display_menu_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-MO] [-b border-lines] [-c target-client] "
"[-C starting-choice] [-H selected-style] [-s style] "
"[-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name [key] [command] ...",
.args = { "c:t:T:x:y:", 1, -1 },
.usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.flags = CMD_AFTERHOOK,
.exec = cmd_display_menu_exec
};
const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
.usage = "[-BCE] [-b border-lines] [-c target-client] "
"[-d start-directory] [-e environment] [-h height] "
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
" [-T title] [-w width] [-x position] [-y position] "
"[shell-command [argument ...]]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_popup_exec
};
static enum args_parse_type
cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
{
u_int i = 0;
enum args_parse_type type = ARGS_PARSE_STRING;
for (;;) {
type = ARGS_PARSE_STRING;
if (i == idx)
break;
if (*args_string(args, i++) == '\0')
continue;
type = ARGS_PARSE_STRING;
if (i++ == idx)
break;
type = ARGS_PARSE_COMMANDS_OR_STRING;
if (i++ == idx)
break;
}
return (type);
}
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 (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 >= tty->sy)
format_add(ft, "popup_mouse_top", "%u", tty->sy - 1);
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_pane_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 (-w %u)", __func__, xp, p, *px, w);
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 (-h %u)", __func__, yp, p, *py, h);
free(p);
format_free(ft);
return (1);
}
static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct client *tc = cmdq_get_target_client(item);
struct args *args = self->args;
struct client *c;
struct session *s = item->target.s;
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 style_range *sr;
struct menu_item menu_item;
const char *key, *name, *value;
const char *style = args_get(args, 's');
const char *border_style = args_get(args, 'S');
const char *selected_style = args_get(args, 'H');
enum box_lines lines = BOX_LINES_DEFAULT;
char *title, *cause;
int flags = 0, starting_choice = 0;
u_int px, py, i, count = args_count(args);
struct options *o = target->s->curw->window->options;
struct options_entry *oe;
const char *xp, *yp, *key;
char *title, *name;
int at, flags, i;
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);
if (args_has(args, 'C')) {
if (strcmp(args_get(args, 'C'), "-") == 0)
starting_choice = -1;
else {
starting_choice = args_strtonum(args, 'C', 0, UINT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "starting choice %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
}
at = status_at_line(c);
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
title = xstrdup("");
menu = menu_create(title);
free(title);
for (i = 0; i != count; /* nothing */) {
name = args_string(args, i++);
menu = menu_create(title);
for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++];
if (*name == '\0') {
menu_add_item(menu, NULL, item, tc, target);
menu_add_item(menu, NULL, item, c, fs);
continue;
}
if (count - i < 2) {
if (args->argc - i < 2) {
cmdq_error(item, "not enough arguments");
free(title);
menu_free(menu);
return (CMD_RETURN_ERROR);
}
key = args_string(args, i++);
key = args->argv[i++];
menu_item.name = name;
menu_item.key = key_string_lookup_string(key);
menu_item.command = args_string(args, 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);
if (menu == NULL) {
cmdq_error(item, "invalid menu arguments");
return (CMD_RETURN_ERROR);
@ -353,150 +104,75 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
if (!cmd_display_menu_get_position(tc, item, args, &px, &py,
menu->width + 4, menu->count + 2)) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
value = args_get(args, 'b');
if (value != NULL) {
oe = options_get(o, "menu-border-lines");
lines = options_find_choice(options_table_entry(oe), value,
&cause);
if (lines == -1) {
cmdq_error(item, "menu-border-lines %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
xp = args_get(args, 'x');
if (xp == NULL)
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 (at == -1)
px = 0;
else {
TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
px = sr->start;
else
px = 0;
}
}
if (args_has(args, 'O'))
flags |= MENU_STAYOPEN;
if (!event->m.valid && !args_has(args, 'M'))
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
style, selected_style, border_style, target, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
{
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, *shellcmd = NULL;
const char *style = args_get(args, 's');
const char *border_style = args_get(args, 'S');
char *cwd, *cause = NULL, **argv = NULL, *title;
int flags = 0, argc = 0;
enum box_lines lines = BOX_LINES_DEFAULT;
u_int px, py, w, h, count = args_count(args);
struct args_value *av;
struct environ *env = NULL;
struct options *o = s->curw->window->options;
struct options_entry *oe;
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);
}
}
w = tty->sx / 2;
if (args_has(args, 'w')) {
w = args_percentage(args, 'w', 1, tty->sx, tty->sx, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (w > tty->sx)
w = tty->sx;
if (h > tty->sy)
h = tty->sy;
if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h))
return (CMD_RETURN_NORMAL);
value = args_get(args, 'b');
if (args_has(args, 'B'))
lines = BOX_LINES_NONE;
else if (value != NULL) {
oe = options_get(o, "popup-border-lines");
lines = options_find_choice(options_table_entry(oe), value,
&cause);
if (cause != NULL) {
cmdq_error(item, "popup-border-lines %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
value = args_get(args, 'd');
if (value != NULL)
cwd = format_single_from_target(item, value);
else
cwd = xstrdup(server_client_get_cwd(tc, s));
if (count == 0)
shellcmd = options_get_string(s->options, "default-command");
else if (count == 1)
shellcmd = args_string(args, 0);
if (count <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
shellcmd = NULL;
shell = options_get_string(s->options, "default-shell");
if (!checkshell(shell))
shell = _PATH_BSHELL;
cmd_append_argv(&argc, &argv, shell);
} else
args_to_vector(args, &argc, &argv);
px = strtoul(xp, NULL, 10);
if (px + menu->width + 4 >= c->tty.sx)
px = c->tty.sx - menu->width - 4;
if (args_has(args, 'e') >= 1) {
env = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(env, av->string, 0);
av = args_next_value(av);
}
}
if (args_has(args, 'T'))
title = format_single_from_target(item, args_get(args, 'T'));
yp = args_get(args, 'y');
if (yp == NULL)
py = 0;
else if (strcmp(yp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->yoff + wp->sy >= oy)
py = wp->yoff + wp->sy - oy;
else
py = 0;
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
py = item->shared->mouse.y + menu->count + 2;
else if (strcmp(yp, "S") == 0) {
if (at == -1)
py = c->tty.sy;
else if (at == 0)
py = status_line_size(c) + menu->count + 2;
else
py = at;
} else
py = strtoul(yp, NULL, 10);
if (py < menu->count + 2)
py = 0;
else
title = xstrdup("");
if (args_has(args, 'E') > 1)
flags |= POPUP_CLOSEEXITZERO;
else if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
cmd_free_argv(argc, argv);
if (env != NULL)
environ_free(env);
free(cwd);
free(title);
py -= menu->count + 2;
if (py + menu->count + 2 >= c->tty.sy)
py = c->tty.sy - menu->count - 2;
flags = 0;
if (!item->shared->mouse.valid)
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
}
if (env != NULL)
environ_free(env);
free(cwd);
free(title);
cmd_free_argv(argc, argv);
return (CMD_RETURN_WAIT);
}

View File

@ -39,13 +39,13 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "aCc:d:lINpt:F:v", 0, 1, NULL },
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] "
.args = { "ac:Ipt:F:v", 0, 1 },
.usage = "[-aIpv] [-c target-client] [-F format] "
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
};
@ -60,53 +60,33 @@ cmd_display_message_each(const char *key, const char *value, void *arg)
static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item), *c;
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct args *args = self->args;
struct client *c, *target_c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *template;
char *msg, *cause;
int delay = -1, flags, Nflag = args_has(args, 'N');
int Cflag = args_has(args, 'C');
struct format_tree *ft;
u_int count = args_count(args);
struct evbuffer *evb;
int flags;
if (args_has(args, 'I')) {
if (wp == NULL)
return (CMD_RETURN_NORMAL);
switch (window_pane_start_input(wp, item, &cause)) {
case -1:
if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
case 1:
return (CMD_RETURN_NORMAL);
case 0:
return (CMD_RETURN_WAIT);
}
return (CMD_RETURN_WAIT);
}
if (args_has(args, 'F') && count != 0) {
if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given");
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);
}
}
if (count != 0)
template = args_string(args, 0);
else
template = args_get(args, 'F');
template = args_get(args, 'F');
if (args->argc != 0)
template = args->argv[0];
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
@ -116,42 +96,28 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
* formats too, assuming it matches the session. If it doesn't, use the
* best client for the session.
*/
if (tc != NULL && tc->session == s)
c = tc;
else if (s != NULL)
c = cmd_find_best_client(s);
c = cmd_find_client(item, args_get(args, 'c'), 1);
if (c != NULL && c->session == s)
target_c = c;
else
c = NULL;
if (args_has(args, 'v'))
target_c = cmd_find_best_client(s);
if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags);
format_defaults(ft, c, s, wl, wp);
ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, target_c, s, wl, wp);
if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l'))
msg = xstrdup(template);
else
msg = format_expand_time(ft, template);
if (cmdq_get_client(item) == NULL)
cmdq_error(item, "%s", msg);
else if (args_has(args, 'p'))
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg);
else if (tc != NULL && (tc->flags & CLIENT_CONTROL)) {
evb = evbuffer_new();
if (evb == NULL)
fatalx("out of memory");
evbuffer_add_printf(evb, "%%message %s", msg);
server_client_print(tc, 0, evb);
evbuffer_free(evb);
} else if (tc != NULL)
status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
else if (c != NULL)
status_message_set(c, "%s", msg);
free(msg);
format_free(ft);

View File

@ -27,34 +27,25 @@
* Display panes on a client.
*/
static enum args_parse_type cmd_display_panes_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.args = { "bd:t:", 0, 1 },
.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec
};
struct cmd_display_panes_data {
struct cmdq_item *item;
struct args_command_state *state;
struct cmdq_item *item;
char *command;
};
static enum args_parse_type
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct window_pane *wp)
@ -64,11 +55,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct session *s = c->session;
struct options *oo = s->options;
struct window *w = wp->window;
struct grid_cell fgc, bgc;
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
struct grid_cell gc;
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour;
char buf[16], lbuf[16], rbuf[16], *ptr;
size_t len, llen, rlen;
char buf[16], *ptr;
size_t len;
if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx ||
@ -118,50 +109,31 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px = sx / 2;
py = sy / 2;
if (window_pane_index(wp, &pane) != 0)
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", pane);
len = xsnprintf(buf, sizeof buf, "%u", idx);
if (sx < len)
return;
colour = options_get_number(oo, "display-panes-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) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
if (sx >= len + llen + 1) {
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;
tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text;
}
px -= len * 3;
py -= 2;
tty_attributes(tty, &bgc, &grid_default_cell, NULL, 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++) {
if (*ptr < '0' || *ptr > '9')
continue;
@ -177,26 +149,27 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px += 6;
}
if (sy <= 6)
goto out;
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
if (rlen != 0 && sx >= rlen) {
tty_cursor(tty, xoff + sx - rlen, yoff);
tty_putn(tty, rbuf, rlen, rlen);
}
if (llen != 0) {
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
yoff + py + 5);
tty_putn(tty, lbuf, llen, llen);
}
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
if (sx < len || sy < 6)
return;
tty_cursor(tty, xoff + sx - len, yoff);
draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.fg = active_colour;
else
gc.fg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
out:
tty_cursor(tty, 0, 0);
}
static void
cmd_display_panes_draw(struct client *c, __unused void *data,
struct screen_redraw_ctx *ctx)
cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
@ -210,58 +183,55 @@ cmd_display_panes_draw(struct client *c, __unused void *data,
}
static void
cmd_display_panes_free(__unused struct client *c, void *data)
cmd_display_panes_free(struct client *c)
{
struct cmd_display_panes_data *cdata = data;
struct cmd_display_panes_data *cdata = c->overlay_data;
if (cdata->item != NULL)
cmdq_continue(cdata->item);
args_make_commands_free(cdata->state);
free(cdata->command);
free(cdata);
}
static int
cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
cmd_display_panes_key(struct client *c, struct key_event *event)
{
struct cmd_display_panes_data *cdata = data;
char *expanded, *error;
struct cmdq_item *item = cdata->item, *new_item;
struct cmd_list *cmdlist;
struct cmd_display_panes_data *cdata = c->overlay_data;
struct cmdq_item *new_item;
char *cmd, *expanded;
struct window *w = c->session->curw->window;
struct window_pane *wp;
u_int index;
key_code key;
struct cmd_parse_result *pr;
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
if (event->key < '0' || event->key > '9')
return (-1);
wp = window_pane_at_index(w, index);
wp = window_pane_at_index(w, event->key - '0');
if (wp == NULL)
return (1);
window_unzoom(w, 1);
window_unzoom(w);
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(cdata->command, expanded, 1);
cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
if (cmdlist == NULL) {
cmdq_append(c, cmdq_get_error(error));
free(error);
} else if (item == NULL) {
new_item = cmdq_get_command(cmdlist, NULL);
pr = cmd_parse_from_string(cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, 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(expanded);
return (1);
}
@ -269,15 +239,18 @@ cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct session *s = tc->session;
u_int delay;
struct args *args = self->args;
struct client *c;
struct session *s;
u_int delay;
char *cause;
struct cmd_display_panes_data *cdata;
int wait = !args_has(args, 'b');
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);
if (args_has(args, 'd')) {
@ -290,23 +263,20 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
} else
delay = options_get_number(s->options, "display-panes-time");
cdata = xcalloc(1, sizeof *cdata);
if (wait)
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->command = xstrdup(args->argv[0]);
else
cdata->command = xstrdup("select-pane -t '%%'");
if (args_has(args, 'b'))
cdata->item = NULL;
else
cdata->item = item;
cdata->state = args_make_commands_prepare(self, item, 0,
"select-pane -t \"%%%\"", wait, 0);
if (args_has(args, 'N')) {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
cdata);
} else {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, cmd_display_panes_key,
cmd_display_panes_free, NULL, cdata);
}
server_client_set_overlay(c, delay, cmd_display_panes_draw,
cmd_display_panes_key, cmd_display_panes_free, cdata);
if (!wait)
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
.args = { "CiNrt:TZ", 1, 1, NULL },
.usage = "[-CiNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.args = { "CNrt:TZ", 1, 1 },
.usage = "[-CNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 },
@ -44,73 +44,82 @@ const struct cmd_entry cmd_find_window_entry = {
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self), *new_args;
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
const char *s = args_string(args, 0), *suffix = "";
const char *star = "*";
struct args_value *filter;
struct args *args = self->args, *new_args;
struct window_pane *wp = item->target.wp;
const char *s = args->argv[0];
char *filter, *argv = { NULL };
int C, N, T;
C = args_has(args, 'C');
N = args_has(args, 'N');
T = args_has(args, 'T');
if (args_has(args, 'r'))
star = "";
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)
C = N = T = 1;
filter = xcalloc(1, sizeof *filter);
filter->type = ARGS_STRING;
if (C && N && T) {
xasprintf(&filter->string,
"#{||:"
"#{C%s:%s},#{||:#{m%s:%s%s%s,#{window_name}},"
"#{m%s:%s%s%s,#{pane_title}}}}",
suffix, s, suffix, star, s, star, suffix, star, s, star);
} else if (C && N) {
xasprintf(&filter->string,
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{window_name}}}",
suffix, s, suffix, star, s, star);
} else if (C && T) {
xasprintf(&filter->string,
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{pane_title}}}",
suffix, s, suffix, star, s, star);
} else if (N && T) {
xasprintf(&filter->string,
"#{||:#{m%s:%s%s%s,#{window_name}},"
"#{m%s:%s%s%s,#{pane_title}}}",
suffix, star, s, star, suffix, star, s, star);
} else if (C) {
xasprintf(&filter->string,
"#{C%s:%s}",
suffix, s);
} else if (N) {
xasprintf(&filter->string,
"#{m%s:%s%s%s,#{window_name}}",
suffix, star, s, star);
if (!args_has(args, 'r')) {
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C:%s}", s);
else if (N)
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
} else {
xasprintf(&filter->string,
"#{m%s:%s%s%s,#{pane_title}}",
suffix, star, s, star);
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_create();
new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL, 0);
args_set(new_args, 'f', filter, 0);
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter);
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args);
free(filter);
return (CMD_RETURN_NORMAL);
}

View File

@ -582,7 +582,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */
if (strcmp(pane, "!") == 0) {
fs->wp = TAILQ_FIRST(&fs->w->last_panes);
fs->wp = fs->w->last;
if (fs->wp == NULL)
return (-1);
return (0);
@ -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 (c->session != NULL) {
cmd_find_clear_state(fs, 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);
cmd_find_from_session(fs, c->session, flags);
return (0);
}
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)) {
fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(cmdq_get_current(item))) {
fs->current = cmdq_get_current(item);
} else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, cmdq_get_client(item),
flags) == 0) {
} else if (cmd_find_from_client(&current, item->client, flags) == 0) {
fs->current = &current;
log_debug("%s: current is from client", __func__);
} else {
@ -992,7 +980,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq_get_event(item)->m;
m = &item->shared->mouse;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@ -1242,31 +1230,29 @@ no_pane:
static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet)
{
struct client *c = NULL, *found;
struct client *c;
struct session *s;
struct window_pane *wp;
struct cmd_find_state fs;
if (item != NULL)
c = cmdq_get_client(item);
if (c != NULL && c->session != NULL)
return (c);
if (item->client != NULL && item->client->session != NULL)
return (item->client);
found = NULL;
if (c != NULL && (wp = cmd_find_inside_pane(c)) != NULL) {
c = NULL;
if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0)
found = cmd_find_best_client(fs.s);
c = cmd_find_best_client(fs.s);
} else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
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");
log_debug("%s: no target, return %p", __func__, found);
return (found);
log_debug("%s: no target, return %p", __func__, c);
return (c);
}
/* Find the target client or report an error and return NULL. */

View File

@ -20,7 +20,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@ -30,19 +29,16 @@
* Executes a tmux command if a shell command returns true or false.
*/
static enum args_parse_type cmd_if_shell_args_parse(struct args *, u_int,
char **);
static enum cmd_retval cmd_if_shell_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell",
.alias = "if",
.args = { "bFt:", 2, 3, cmd_if_shell_args_parse },
.args = { "bFt:", 2, 3 },
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]",
@ -53,75 +49,102 @@ const struct cmd_entry cmd_if_shell_entry = {
};
struct cmd_if_shell_data {
struct args_command_state *cmd_if;
struct args_command_state *cmd_else;
struct cmd_parse_input input;
struct client *client;
struct cmdq_item *item;
char *cmd_if;
char *cmd_else;
struct client *client;
struct cmdq_item *item;
struct mouse_event mouse;
};
static enum args_parse_type
cmd_if_shell_args_parse(__unused struct args *args, u_int idx,
__unused char **cause)
{
if (idx == 1 || idx == 2)
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct args *args = self->args;
struct mouse_event *m = &item->shared->mouse;
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd;
struct cmdq_item *new_item;
char *shellcmd;
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct cmd_list *cmdlist;
u_int count = args_count(args);
int wait = !args_has(args, 'b');
struct cmd_find_state *fs = &item->target;
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_result *pr;
shellcmd = format_single_from_target(item, args_string(args, 0));
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) {
if (*shellcmd != '0' && *shellcmd != '\0')
cmdlist = args_make_commands_now(self, item, 1, 0);
else if (count == 3)
cmdlist = args_make_commands_now(self, item, 2, 0);
else {
free(shellcmd);
return (CMD_RETURN_NORMAL);
}
cmd = args->argv[1];
else if (args->argc == 3)
cmd = args->argv[2];
else
cmd = NULL;
free(shellcmd);
if (cmdlist == NULL)
if (cmd == NULL)
return (CMD_RETURN_NORMAL);
memset(&pi, 0, sizeof pi);
if (self->file != NULL)
pi.file = self->file;
pi.line = self->line;
pi.item = item;
pi.c = c;
cmd_find_copy_state(&pi.fs, fs);
pr = cmd_parse_from_string(cmd, &pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR);
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item);
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);
}
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd_if = args_make_commands_prepare(self, item, 1, NULL, wait,
0);
if (count == 3) {
cdata->cmd_else = args_make_commands_prepare(self, item, 2,
NULL, wait, 0);
}
cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
if (wait) {
cdata->client = cmdq_get_client(item);
cdata->item = item;
} else
cdata->client = tc;
if (!args_has(args, 'b'))
cdata->client = item->client;
else
cdata->client = c;
if (cdata->client != NULL)
cdata->client->references++;
if (job_run(shellcmd, 0, NULL, NULL, s,
server_client_get_cwd(cmdq_get_client(item), s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
-1) == NULL) {
if (!args_has(args, 'b'))
cdata->item = item;
else
cdata->item = NULL;
memset(&cdata->input, 0, sizeof cdata->input);
if (self->file != NULL)
cdata->input.file = xstrdup(self->file);
cdata->input.line = self->line;
cdata->input.item = cdata->item;
cdata->input.c = c;
if (cdata->input.c != NULL)
cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
@ -129,7 +152,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
}
free(shellcmd);
if (!wait)
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
@ -139,34 +162,39 @@ cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client;
struct cmdq_item *item = cdata->item, *new_item;
struct args_command_state *state;
struct cmd_list *cmdlist;
char *error;
struct mouse_event *m = &cdata->mouse;
struct cmdq_item *new_item = NULL;
char *cmd;
int status;
struct cmd_parse_result *pr;
status = job_get_status(job);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
state = cdata->cmd_else;
cmd = cdata->cmd_else;
else
state = cdata->cmd_if;
if (state == NULL)
cmd = cdata->cmd_if;
if (cmd == NULL)
goto out;
cmdlist = args_make_commands(state, 0, NULL, &error);
if (cmdlist == NULL) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);
} else if (item == NULL) {
new_item = cmdq_get_command(cmdlist, NULL);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item);
pr = cmd_parse_from_string(cmd, &cdata->input);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (cdata->item != NULL)
cmdq_error(cdata->item, "%s", pr->error);
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
cmd_list_free(pr->cmdlist);
break;
}
if (new_item != NULL) {
if (cdata->item == NULL)
cmdq_append(c, new_item);
else
cmdq_insert_after(cdata->item, new_item);
}
out:
@ -182,9 +210,12 @@ cmd_if_shell_free(void *data)
if (cdata->client != NULL)
server_client_unref(cdata->client);
if (cdata->cmd_else != NULL)
args_make_commands_free(cdata->cmd_else);
args_make_commands_free(cdata->cmd_if);
free(cdata->cmd_else);
free(cdata->cmd_if);
if (cdata->input.c != NULL)
server_client_unref(cdata->input.c);
free((void *)cdata->input.file);
free(cdata);
}

View File

@ -20,7 +20,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@ -35,8 +34,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane",
.alias = "joinp",
.args = { "bdfhvp:l:s:t:", 0, 0, NULL },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@ -49,10 +48,10 @@ const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane",
.alias = "movep",
.args = { "bdfhvp:l:s:t:", 0, 0, NULL },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
@ -62,34 +61,40 @@ const struct cmd_entry cmd_move_pane_entry = {
static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
char *cause = NULL;
int size, dst_idx;
int flags;
char *cause;
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
u_int curval = 0;
int not_same_window, flags;
dst_s = target->s;
dst_wl = target->wl;
dst_wp = target->wp;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
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_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = source->wl;
src_wp = source->wp;
src_wl = item->source.wl;
src_wp = item->source.wp;
src_w = src_wl->window;
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");
return (CMD_RETURN_ERROR);
}
@ -98,43 +103,30 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
if (args_has(args, 'l') || args_has(args, 'p')) {
if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
curval = dst_w->sy;
else
curval = dst_w->sx;
} else {
if (type == LAYOUT_TOPBOTTOM)
curval = dst_wp->sy;
else
curval = dst_wp->sx;
}
}
size = -1;
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause);
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')) {
size = args_strtonum_and_expand(args, 'l', 0, 100, item,
&cause);
if (cause == NULL)
size = curval * size / 100;
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
cmdq_error(item, "percentage %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
flags = 0;
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
flags = SPAWN_BEFORE;
else
flags = 0;
lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
@ -143,19 +135,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(src_wp);
server_client_remove_pane(src_wp);
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0);
colour_palette_from_option(&src_wp->palette, src_wp->options);
src_wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
recalculate_sizes();
@ -171,7 +158,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_status_session(dst_s);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w, 1);
server_kill_window(src_w);
else
notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w);

View File

@ -32,29 +32,26 @@ const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane",
.alias = "killp",
.args = { "at:", 0, 0, NULL },
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.flags = 0,
.exec = cmd_kill_pane_exec
};
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
if (args_has(args, 'a')) {
if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
server_client_remove_pane(loopwp);
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server",
.alias = NULL,
.args = { "", 0, 0, NULL },
.args = { "", 0, 0 },
.usage = "",
.flags = 0,
@ -44,7 +44,7 @@ const struct cmd_entry cmd_start_server_entry = {
.name = "start-server",
.alias = "start",
.args = { "", 0, 0, NULL },
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_STARTSERVER,
@ -54,7 +54,7 @@ const struct cmd_entry cmd_start_server_entry = {
static enum cmd_retval
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);
return (CMD_RETURN_NORMAL);

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session",
.alias = NULL,
.args = { "aCt:", 0, 0, NULL },
.args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -45,10 +45,11 @@ const struct cmd_entry cmd_kill_session_entry = {
static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s, *sloop, *stmp;
struct winlink *wl;
struct args *args = self->args;
struct session *s, *sloop, *stmp;
struct winlink *wl;
s = item->target.s;
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {

View File

@ -30,7 +30,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window",
.alias = "killw",
.args = { "at:", 0, 0, NULL },
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -43,7 +43,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
.name = "unlink-window",
.alias = "unlinkw",
.args = { "kt:", 0, 0, NULL },
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -55,56 +55,27 @@ const struct cmd_entry cmd_unlink_window_entry = {
static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl, *loop;
struct args *args = self->args;
struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window;
struct session *s = target->s;
u_int found;
struct session *s = item->target.s;
if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
if (!args_has(args, 'k') && !session_is_linked(s, w)) {
if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'a')) {
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;
}
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
} while (found != 0);
/*
* 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);
} else
server_kill_window(wl->window);
}
server_kill_window(wl->window, 1);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}

View File

@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers",
.alias = "lsb",
.args = { "F:f:", 0, 0, NULL },
.usage = "[-F format] [-f filter]",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec
@ -46,33 +46,23 @@ const struct cmd_entry cmd_list_buffers_entry = {
static enum cmd_retval
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 format_tree *ft;
const char *template, *filter;
char *line, *expanded;
int flag;
char *line;
const char *template;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
filter = args_get(args, 'f');
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);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
}

View File

@ -28,12 +28,10 @@
* List all clients.
*/
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \
"#{?#{!=:#{client_uid},#{uid}}," \
"[user #{?client_user,#{client_user},#{client_uid},}] ,}" \
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
@ -41,8 +39,8 @@ const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients",
.alias = "lsc",
.args = { "F:f:t:", 0, 0, NULL },
.usage = "[-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
.args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -53,45 +51,34 @@ const struct cmd_entry cmd_list_clients_entry = {
static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct args *args = self->args;
struct client *c;
struct session *s;
struct format_tree *ft;
const char *template, *filter;
const char *template;
u_int idx;
char *line, *expanded;
int flag;
char *line;
if (args_has(args, 't'))
s = target->s;
s = item->target.s;
else
s = NULL;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE;
filter = args_get(args, 'f');
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (s != NULL && s != c->session))
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_defaults(ft, c, NULL, NULL, NULL);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);

View File

@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
.alias = "lsk",
.args = { "1aNP:T:", 0, 1, NULL },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
.args = { "T:", 0, 0 },
.usage = "[-T key-table]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
@ -47,172 +47,36 @@ const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 1, NULL },
.usage = "[-F format] [command]",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
};
static u_int
cmd_list_keys_get_width(const char *tablename, key_code only)
{
struct key_table *table;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
return (keywidth);
}
static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{
struct client *tc = cmdq_get_target_client(item);
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = key_string_lookup_key(bd->key, 0);
if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist, 1);
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
tmp, note);
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
}
static char *
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
{
char *s;
*prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
else
s = xstrdup("");
} else
s = xstrdup(args_get(args, 'P'));
return (s);
}
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct args *args = self->args;
struct key_table *table;
struct key_binding *bd;
const char *tablename, *r, *keystr;
char *key, *cp, *tmp, *start, *empty;
key_code prefix, only = KEYC_UNKNOWN;
int repeat, width, tablewidth, keywidth, found = 0;
const char *tablename, *r;
char *key, *cp, *tmp;
int repeat, width, tablewidth, keywidth;
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));
if ((keystr = args_string(args, 0)) != NULL) {
only = key_string_lookup_string(keystr);
if (only == KEYC_UNKNOWN) {
cmdq_error(item, "invalid key: %s", keystr);
return (CMD_RETURN_ERROR);
}
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
}
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
}
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root",
keywidth, only, empty);
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args,
"prefix", keywidth, only, start))
found = 1;
}
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else
start = xstrdup("");
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
}
free(start);
goto out;
}
repeat = 0;
tablewidth = keywidth = 0;
table = key_bindings_first_table();
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
@ -220,11 +84,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
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)
repeat = 1;
@ -245,7 +105,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize = 256;
tmp = xmalloc(tmpsize);
table = key_bindings_first_table();
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
@ -253,12 +113,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0));
key = args_escape(key_string_lookup_key(bd->key));
if (!repeat)
r = "";
@ -274,7 +129,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
@ -284,7 +139,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
@ -297,15 +152,9 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
strlcat(tmp, cp, tmpsize);
free(cp);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0,
"bind-key %s", tmp);
} else
cmdq_print(item, "bind-key %s", tmp);
free(key);
cmdq_print(item, "bind-key %s", tmp);
if (args_has(args, '1'))
break;
free(key);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
@ -313,48 +162,18 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args_string(args, 0));
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
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 *entry;
struct format_tree *ft;
const char *template, *command;
char *cause;
const char *template, *s;
char *line;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
@ -362,23 +181,28 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{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);
command = args_string(args, 0);
if (command == NULL) {
for (entryp = cmd_table; *entryp != NULL; entryp++)
cmd_list_single_command(*entryp, ft, template, item);
} else {
entry = cmd_find(command, &cause);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);

View File

@ -38,8 +38,8 @@ const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes",
.alias = "lsp",
.args = { "asF:f:t:", 0, 0, NULL },
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE,
.args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -50,10 +50,9 @@ const struct cmd_entry cmd_list_panes_entry = {
static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct args *args = self->args;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
if (args_has(args, 'a'))
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,
struct cmdq_item *item, int type)
{
struct args *args = cmd_get_args(self);
struct args *args = self->args;
struct window_pane *wp;
u_int n;
struct format_tree *ft;
const char *template, *filter;
char *line, *expanded;
int flag;
const char *template;
char *line;
template = args_get(args, 'F');
if (template == NULL) {
@ -122,25 +120,16 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
break;
}
}
filter = args_get(args, 'f');
n = 0;
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_defaults(ft, NULL, s, wl, wp);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
n++;

View File

@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions",
.alias = "ls",
.args = { "F:f:", 0, 0, NULL },
.usage = "[-F format] [-f filter]",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec
@ -52,35 +52,25 @@ const struct cmd_entry cmd_list_sessions_entry = {
static enum cmd_retval
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;
u_int n;
struct format_tree *ft;
const char *template, *filter;
char *line, *expanded;
int flag;
const char *template;
char *line;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
filter = args_get(args, 'f');
n = 0;
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_defaults(ft, NULL, s, NULL, NULL);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
n++;

View File

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

View File

@ -33,81 +33,151 @@
static enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmdq_item *);
static void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer",
.alias = "loadb",
.args = { "b:t:w", 1, 1, NULL },
.usage = CMD_BUFFER_USAGE " " CMD_TARGET_CLIENT_USAGE " path",
.args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
.flags = CMD_AFTERHOOK,
.exec = cmd_load_buffer_exec
};
struct cmd_load_buffer_data {
struct client *client;
struct cmdq_item *item;
char *name;
char *bufname;
};
static void
cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data)
{
struct cmd_load_buffer_data *cdata = data;
struct client *tc = cdata->client;
struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer);
void *copy;
char *cause;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) {
copy = xmalloc(bsize);
memcpy(copy, bdata, bsize);
if (paste_set(copy, bsize, cdata->name, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
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);
free(cdata->name);
free(cdata);
}
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct args *args = self->args;
struct cmd_load_buffer_data *cdata;
const char *bufname = args_get(args, 'b');
char *path;
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;
FILE *f;
const char *bufname;
char *pdata = NULL, *new_pdata, *cause;
char *path, *file;
size_t psize;
int ch, error;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (bufname != NULL)
cdata->name = xstrdup(bufname);
if (args_has(args, 'w') && tc != NULL) {
cdata->client = tc;
cdata->client->references++;
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (bufname != NULL)
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
cdata, &cause);
if (error != 0) {
cmdq_error(item, "-: %s", cause);
free(cause);
free(cdata);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
}
path = format_single_from_target(item, args_string(args, 0));
file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata);
file = server_client_get_path(item->client, path);
free(path);
return (CMD_RETURN_WAIT);
f = fopen(file, "rb");
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
goto error;
}
pdata = NULL;
psize = 0;
while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(item, "realloc error: %s", strerror(errno));
goto error;
}
pdata = new_pdata;
pdata[psize++] = ch;
}
if (ferror(f)) {
cmdq_error(item, "%s: read error", file);
goto error;
}
if (pdata != NULL)
pdata[psize] = '\0';
fclose(f);
free(file);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
error:
free(pdata);
if (f != NULL)
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}
static void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
struct cmd_load_buffer_data *cdata = data;
char *pdata, *cause, *saved;
size_t psize;
if (!closed)
return;
c->stdin_callback = NULL;
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
goto out;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) {
saved = cause;
cause = utf8_sanitize(saved);
free(saved);
}
evbuffer_add_printf(c->stderr_data, "%s", cause);
server_client_push_stderr(c);
free(pdata);
free(cause);
}
out:
cmdq_continue(cdata->item);
free(cdata->bufname);
free(cdata);
}

View File

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

View File

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

View File

@ -39,11 +39,10 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1, NULL },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
"[shell-command [argument ...]]",
.args = { "Ac:dDEF:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -55,7 +54,7 @@ const struct cmd_entry cmd_has_session_entry = {
.name = "has-session",
.alias = "has",
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -67,26 +66,22 @@ const struct cmd_entry cmd_has_session_entry = {
static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct session *s, *as, *groupwith = NULL;
struct args *args = self->args;
struct client *c = item->client;
struct session *s, *as, *groupwith;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg = NULL;
const char *errstr, *template, *group, *tmp;
struct session_group *sg;
const char *errstr, *template, *group, *prefix, *tmp;
char *cause, *cwd = NULL, *cp, *newname = NULL;
char *name, *prefix = NULL;
int detached, already_attached, is_control = 0;
u_int sx, sy, dsx, dsy, count = args_count(args);
struct spawn_context sc = { 0 };
u_int sx, sy, dsx, dsy;
struct spawn_context sc;
enum cmd_retval retval;
struct cmd_find_state fs;
struct args_value *av;
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,
* so always return success here.
@ -94,60 +89,54 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 't') && (count != 0 || args_has(args, 'n'))) {
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(item, "command or window name given with target");
return (CMD_RETURN_ERROR);
}
tmp = args_get(args, 's');
if (tmp != NULL) {
name = format_single(item, tmp, c, NULL, NULL, NULL);
newname = session_check_name(name);
if (newname == NULL) {
cmdq_error(item, "invalid session: %s", name);
free(name);
return (CMD_RETURN_ERROR);
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
goto fail;
}
free(name);
}
if (args_has(args, 'A')) {
if (newname != NULL)
as = session_find(newname);
else
as = target->s;
if (as != NULL) {
retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E'), args_get(args, 'f'));
free(newname);
return (retval);
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
retval = cmd_attach_session(item,
newname, args_has(args, 'D'),
args_has(args, 'X'), 0, NULL,
args_has(args, 'E'));
free(newname);
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
goto fail;
}
}
if (newname != NULL && session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
goto fail;
}
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = target->s;
if (groupwith == NULL)
sg = session_group_find(group);
else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = xstrdup(sg->name);
else if (groupwith != NULL)
prefix = xstrdup(groupwith->name);
else {
prefix = session_check_name(group);
if (prefix == NULL) {
cmdq_error(item, "invalid session group: %s",
group);
groupwith = item->target.s;
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
goto fail;
}
}
sg = session_group_find(group);
} else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
else if (groupwith != NULL)
prefix = groupwith->name;
else
prefix = group;
} else {
groupwith = NULL;
sg = NULL;
prefix = NULL;
}
/* Set -d if no client. */
@ -177,16 +166,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* the terminal as that calls tcsetattr() to prepare for tmux taking
* over.
*/
if (!detached &&
!already_attached &&
c->fd != -1 &&
(~c->flags & CLIENT_CONTROL)) {
if (server_client_check_nested(cmdq_get_client(item))) {
if (!detached && !already_attached && c->tty.fd != -1) {
if (server_client_check_nested(item->client)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
goto fail;
}
if (tcgetattr(c->fd, &tio) != 0)
if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
tiop = &tio;
} else
@ -216,8 +202,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
} else
dsx = 80;
}
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
@ -232,8 +217,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
} else
dsy = 24;
}
/* Find new session size. */
if (!detached && !is_control) {
@ -244,14 +228,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else {
tmp = options_get_string(global_s_options, "default-size");
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = dsx;
sy = dsy;
} else {
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
sx = 80;
sy = 24;
}
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
}
if (sx == 0)
sx = 1;
@ -270,21 +253,16 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(env, av->string, 0);
av = args_next_value(av);
}
s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Spawn the initial window. */
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
if (!detached)
sc.tc = c;
sc.name = args_get(args, 'n');
args_to_vector(args, &sc.argc, &sc.argv);
sc.argc = args->argc;
sc.argv = args->argv;
sc.idx = -1;
sc.cwd = args_get(args, 'c');
@ -321,50 +299,54 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) {
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
server_client_set_session(c, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
}
recalculate_sizes();
server_update_socket();
/*
* If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now.
*/
if (cfg_finished)
cfg_show_causes(s);
/* Print if requested. */
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE;
cp = format_single(item, template, c, s, s->curw, NULL);
cp = format_single(item, template, c, s, NULL, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
if (!detached)
if (!detached) {
c->flags |= CLIENT_ATTACHED;
if (!args_has(args, 'd'))
cmd_find_from_session(current, s, 0);
cmd_find_from_session(&item->shared->current, s, 0);
}
cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session");
if (cfg_finished)
cfg_show_causes(s);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
free(cwd);
free(newname);
free(prefix);
return (CMD_RETURN_NORMAL);
fail:
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
free(cwd);
free(newname);
free(prefix);
return (CMD_RETURN_ERROR);
}

View File

@ -38,10 +38,9 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE
" [shell-command [argument ...]]",
.args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@ -52,70 +51,37 @@ const struct cmd_entry cmd_new_window_entry = {
static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc = { 0 };
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl, *new_wl = NULL;
int idx = target->idx, before;
char *cause = NULL, *cp, *expanded;
const char *template, *name;
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct spawn_context sc;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
int idx = item->target.idx;
struct winlink *new_wl;
char *cause = NULL, *cp;
const char *template, *add;
struct cmd_find_state fs;
struct args_value *av;
struct args_value *value;
/*
* If -S and -n are given and -t is not and a single window with this
* name already exists, select it.
*/
name = args_get(args, 'n');
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
expanded = format_single(item, name, c, s, NULL, NULL);
RB_FOREACH(wl, winlinks, &s->windows) {
if (strcmp(wl->window->name, expanded) != 0)
continue;
if (new_wl == NULL) {
new_wl = wl;
continue;
}
cmdq_error(item, "multiple windows named %s", name);
free(expanded);
return (CMD_RETURN_ERROR);
}
free(expanded);
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;
if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "couldn't get a window index");
return (CMD_RETURN_ERROR);
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.tc = tc;
sc.name = args_get(args, 'n');
args_to_vector(args, &sc.argc, &sc.argv);
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(sc.environ, av->string, 0);
av = args_next_value(av);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = idx;
@ -130,9 +96,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
}
if (!args_has(args, 'd') || new_wl == s->curw) {
@ -144,8 +107,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, tc, s, new_wl,
new_wl->window->active);
cp = format_single(item, template, c, s, new_wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
@ -153,8 +115,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink(&fs, new_wl, 0);
cmdq_insert_hook(s, item, &fs, "after-new-window");
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer",
.alias = "pasteb",
.args = { "db:prs:t:", 0, 0, NULL },
.args = { "db:prs:t:", 0, 0 },
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE,
@ -46,19 +46,13 @@ const struct cmd_entry cmd_paste_buffer_entry = {
static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
struct args *args = self->args;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;
int bracket = args_has(args, 'p');
if (window_pane_exited(wp)) {
cmdq_error(item, "target pane has exited");
return (CMD_RETURN_ERROR);
}
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');

View File

@ -43,8 +43,8 @@ const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane",
.alias = "pipep",
.args = { "IOot:", 0, 1, NULL },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [shell-command]",
.args = { "IOot:", 0, 1 },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -55,23 +55,15 @@ const struct cmd_entry cmd_pipe_pane_entry = {
static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct window_pane *wp = target->wp;
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane_offset *wpo = &wp->pipe_offset;
char *cmd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
/* Do nothing if pane is dead. */
if (window_pane_exited(wp)) {
cmdq_error(item, "target pane has exited");
return (CMD_RETURN_ERROR);
}
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
@ -87,7 +79,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* If no pipe command, that is enough. */
if (args_count(args) == 0 || *args_string(args, 0) == '\0')
if (args->argc == 0 || *args->argv[0] == '\0')
return (CMD_RETURN_NORMAL);
/*
@ -96,13 +88,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
*
* 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);
/* 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;
out = args_has(args, 'O');
out = args_has(self->args, 'O');
} else {
in = 0;
out = 1;
@ -115,9 +107,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* Expand the command. */
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, tc, s, wl, wp);
cmd = format_expand_time(ft, args_string(args, 0));
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0]);
format_free(ft);
/* Fork the child. */
@ -136,7 +128,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[0]);
null_fd = open(_PATH_DEVNULL, O_WRONLY);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (out) {
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
@ -165,7 +157,10 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
close(pipe_fd[1]);
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);
wp->pipe_event = bufferevent_new(wp->pipe_fd,

View File

@ -19,77 +19,14 @@
#include <sys/types.h>
#include <ctype.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
/* Command queue flags. */
#define CMDQ_FIRED 0x1
#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;
};
/* Global command queue. */
static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Get command queue name. */
static const char *
@ -110,194 +47,13 @@ cmdq_name(struct client *c)
static struct cmdq_list *
cmdq_get(struct client *c)
{
static struct cmdq_list *global_queue;
if (c == NULL) {
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, struct cmd_find_state *current)
{
if (current != NULL)
return (cmdq_new_state(current, &state->event, state->flags));
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);
}
/* Add formats to command queue. */
void
cmdq_add_formats(struct cmdq_state *state, struct format_tree *ft)
{
if (state->formats == NULL)
state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_merge(state->formats, ft);
}
/* 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);
if (c == NULL)
return (&global_queue);
return (&c->queue);
}
/* Append an item. */
struct cmdq_item *
void
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
@ -312,16 +68,15 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->client = c;
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);
item = next;
} while (item != NULL);
return (TAILQ_LAST(&queue->list, cmdq_item_list));
}
/* Insert an item. */
struct cmdq_item *
void
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
@ -338,38 +93,30 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
item->client = c;
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),
item->name, after->name);
after = item;
item = next;
} while (item != NULL);
return (after);
}
/* Insert a hook. */
void
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 *ae;
struct args_value *av;
struct options *oo;
va_list ap;
char *name, tmp[32], flag, *arguments;
u_int i;
const char *value;
char *name;
struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
if (item->state->flags & CMDQ_STATE_NOHOOKS)
if (item->flags & CMDQ_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
@ -387,58 +134,25 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *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_count(args); i++) {
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
cmdq_add_format(new_state, tmp, "%s", args_string(args, i));
}
flag = args_first(args, &ae);
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;
av = args_first_value(args, flag);
while (av != NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
cmdq_add_format(new_state, tmp, "%s", av->string);
i++;
av = args_next_value(av);
}
flag = args_next(&ae);
}
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) {
new_item = cmdq_get_command(cmdlist, new_state);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
if (cmdlist == NULL) {
a = options_array_next(a);
continue;
}
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL) {
cmdq_insert_after(item, new_item);
item = new_item;
} else
cmdq_append(NULL, new_item);
a = options_array_next(a);
}
cmdq_free_state(new_state);
free(name);
}
@ -453,13 +167,19 @@ cmdq_continue(struct cmdq_item *item)
static void
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)
server_client_unref(item->client);
if (item->cmdlist != NULL)
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);
@ -482,57 +202,50 @@ cmdq_remove_group(struct cmdq_item *item)
}
}
/* Empty command callback. */
static enum cmd_retval
cmdq_empty_command(__unused struct cmdq_item *item, __unused void *data)
{
return (CMD_RETURN_NORMAL);
}
/* Get a command for the command queue. */
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 cmd *cmd;
const struct cmd_entry *entry;
int created = 0;
struct cmdq_shared *shared = NULL;
u_int group = 0;
if ((cmd = cmd_list_first(cmdlist)) == NULL)
return (cmdq_get_callback(cmdq_empty_command, NULL));
if (state == NULL) {
state = cmdq_new_state(NULL, NULL, 0);
created = 1;
}
while (cmd != NULL) {
entry = cmd_get_entry(cmd);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->group != group) {
shared = xcalloc(1, sizeof *shared);
if (current != NULL)
cmd_find_copy_state(&shared->current, current);
else
cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
group = cmd->group;
}
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->group = cmd_get_group(cmd);
item->state = cmdq_link_state(state);
item->group = cmd->group;
item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
cmdlist->references++;
log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
cmd = cmd_list_next(cmd);
}
if (created)
cmdq_free_state(state);
return (first);
}
@ -544,11 +257,11 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const char *value;
if (flag->flag == 0) {
cmd_find_from_client(fs, item->target_client, 0);
cmd_find_clear_state(fs, 0);
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) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
@ -556,89 +269,31 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
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 *key;
char *tmp;
uid_t uid;
struct passwd *pw;
char *user = NULL;
tmp = cmd_print(item->cmd);
if (c != NULL) {
uid = proc_get_peer_uid(c->peer);
if (uid != (uid_t)-1 && uid != getuid()) {
if ((pw = getpwuid(uid)) != NULL)
xasprintf(&user, "[%s]", pw->pw_name);
else
user = xstrdup("[unknown]");
} else
user = xstrdup("");
if (c->session != NULL && state->event.key != KEYC_NONE) {
key = key_string_lookup_key(state->event.key, 0);
server_add_message("%s%s key %s: %s", c->name, user,
key, tmp);
} else {
server_add_message("%s%s command: %s", c->name, user,
tmp);
}
free(user);
} else
server_add_message("command: %s", tmp);
free(tmp);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
const char *name = cmdq_name(item->client);
struct cmdq_state *state = item->state;
struct client *c = item->client;
const char *name = cmdq_name(c);
struct cmdq_shared *shared = item->shared;
struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd);
const struct cmd_entry *entry = cmd_get_entry(cmd);
struct client *tc, *saved = item->client;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval;
struct cmd_find_state *fsp, fs;
int flags, quiet = 0;
int flags;
char *tmp;
if (cfg_finished)
cmdq_add_message(item);
if (log_get_level() > 1) {
tmp = cmd_print(cmd);
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
free(tmp);
}
flags = !!(state->flags & CMDQ_STATE_CONTROL);
flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
cmdq_guard(item, "begin", flags);
if (item->client == NULL)
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);
if (retval == CMD_RETURN_ERROR)
goto out;
@ -653,8 +308,8 @@ cmdq_fire_command(struct cmdq_item *item)
if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current))
fsp = &item->state->current;
else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
else
@ -663,19 +318,10 @@ cmdq_fire_command(struct cmdq_item *item)
}
out:
item->client = saved;
if (retval == CMD_RETURN_ERROR) {
fsp = NULL;
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current))
fsp = &item->state->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
cmdq_insert_hook(fsp != NULL ? fsp->s : NULL, item, fsp,
"command-error");
item->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
} else
else
cmdq_guard(item, "end", flags);
return (retval);
}
@ -691,7 +337,7 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
item->type = CMDQ_CALLBACK;
item->group = 0;
item->state = cmdq_new_state(NULL, NULL, 0);
item->flags = 0;
item->cb = cb;
item->data = data;
@ -725,6 +371,25 @@ cmdq_fire_callback(struct cmdq_item *item)
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. */
u_int
cmdq_next(struct client *c)
@ -736,18 +401,18 @@ cmdq_next(struct client *c)
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(&queue->list)) {
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) {
if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
log_debug("%s %s: enter", __func__, name);
for (;;) {
item = queue->item = TAILQ_FIRST(&queue->list);
item = TAILQ_FIRST(queue);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
@ -797,7 +462,6 @@ cmdq_next(struct client *c)
}
cmdq_remove(item);
}
queue->item = NULL;
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
@ -807,55 +471,54 @@ waiting:
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. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
{
struct client *c = item->client;
long t = item->time;
u_int number = item->number;
if (c != NULL && (c->flags & CLIENT_CONTROL))
control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
}
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
/* Show message from command. */
void
cmdq_print_data(struct cmdq_item *item, struct evbuffer *evb)
{
server_client_print(item->client, 1, evb);
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)item->time, item->number, flags);
server_client_push_stdout(c);
}
/* Show message from command. */
void
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{
va_list ap;
struct evbuffer *evb;
evb = evbuffer_new();
if (evb == NULL)
fatalx("out of memory");
struct client *c = item->client;
struct window_pane *wp;
struct window_mode_entry *wme;
va_list ap;
char *tmp, *msg;
va_start(ap, fmt);
evbuffer_add_vprintf(evb, fmt, ap);
va_end(ap);
cmdq_print_data(item, evb);
evbuffer_free(evb);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
xvasprintf(&tmp, fmt, ap);
msg = utf8_sanitize(tmp);
free(tmp);
evbuffer_add(c->stdout_data, msg, strlen(msg));
free(msg);
} else
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_vadd(wp, fmt, ap);
}
va_end(ap);
}
/* Show error from command. */
@ -865,34 +528,32 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
struct client *c = item->client;
struct cmd *cmd = item->cmd;
va_list ap;
char *msg, *tmp;
const char *file;
u_int line;
char *msg;
size_t msglen;
char *tmp;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL) {
cmd_get_source(cmd, &file, &line);
cfg_add_cause("%s:%u: %s", file, line, msg);
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
server_add_message("%s message: %s", c->name, msg);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
msglen = strlen(msg);
}
if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg);
else
file_error(c, "%s\n", msg);
evbuffer_add(c->stderr_data, msg, msglen);
evbuffer_add(c->stderr_data, "\n", 1);
server_client_push_stderr(c);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, -1, 1, 0, 0, "%s", msg);
status_message_set(c, "%s", msg);
}
free(msg);

View File

@ -34,204 +34,28 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
" [adjustment]",
.args = { "cC:DF:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
" [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.flags = CMD_AFTERHOOK,
.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 enum cmd_retval
cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
const char *size = args_get(args, 'C');
u_int w, x, y;
struct client_window *cw;
if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
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);
}
log_debug("%s: client %s window @%u: size %ux%u", __func__,
tc->name, w, x, y);
cw = server_client_add_client_window(tc, w);
cw->sx = x;
cw->sy = y;
tc->flags |= CLIENT_WINDOWSIZECHANGED;
recalculate_sizes_now(1);
return (CMD_RETURN_NORMAL);
}
if (sscanf(size, "@%u:", &w) == 1) {
cw = server_client_get_client_window(tc, w);
if (cw != NULL) {
log_debug("%s: client %s window @%u: no size", __func__,
tc->name, w);
cw->sx = 0;
cw->sy = 0;
recalculate_sizes_now(1);
}
return (CMD_RETURN_NORMAL);
}
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);
}
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
cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
const char *p;
u_int i;
struct cmd_find_state fs;
p = args_get(args, 'l');
if (p == NULL) {
if (tc->flags & CLIENT_CLIPBOARDBUFFER)
return (CMD_RETURN_NORMAL);
tc->flags |= CLIENT_CLIPBOARDBUFFER;
} else {
if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
return (CMD_RETURN_ERROR);
for (i = 0; i < tc->clipboard_npanes; i++) {
if (tc->clipboard_panes[i] == fs.wp->id)
break;
}
if (i != tc->clipboard_npanes)
return (CMD_RETURN_NORMAL);
tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
}
tty_clipboard_query(&tc->tty);
return (CMD_RETURN_NORMAL);
}
static void
cmd_refresh_report(struct tty *tty, const char *value)
{
struct window_pane *wp;
u_int pane;
size_t size = 0;
char *copy, *split;
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;
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
&wp->control_bg);
out:
free(copy);
}
static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct tty *tty = &tc->tty;
struct window *w;
const char *errstr;
u_int adjust;
struct args_value *av;
struct args *args = self->args;
struct client *c;
struct tty *tty;
struct window *w;
const char *size, *errstr;
char *copy, *next, *s;
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') ||
args_has(args, 'L') ||
@ -239,11 +63,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
args_has(args, 'U') ||
args_has(args, 'D'))
{
if (args_count(args) == 0)
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX,
&errstr);
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
@ -251,85 +74,88 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'c'))
tc->pan_window = NULL;
c->pan_window = NULL;
else {
w = tc->session->curw->window;
if (tc->pan_window != w) {
tc->pan_window = w;
tc->pan_ox = tty->oox;
tc->pan_oy = tty->ooy;
w = c->session->curw->window;
if (c->pan_window != w) {
c->pan_window = w;
c->pan_ox = tty->oox;
c->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
if (tc->pan_ox > adjust)
tc->pan_ox -= adjust;
if (c->pan_ox > adjust)
c->pan_ox -= adjust;
else
tc->pan_ox = 0;
c->pan_ox = 0;
} else if (args_has(args, 'R')) {
tc->pan_ox += adjust;
if (tc->pan_ox > w->sx - tty->osx)
tc->pan_ox = w->sx - tty->osx;
c->pan_ox += adjust;
if (c->pan_ox > w->sx - tty->osx)
c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
if (tc->pan_oy > adjust)
tc->pan_oy -= adjust;
if (c->pan_oy > adjust)
c->pan_oy -= adjust;
else
tc->pan_oy = 0;
c->pan_oy = 0;
} else if (args_has(args, 'D')) {
tc->pan_oy += adjust;
if (tc->pan_oy > w->sy - tty->osy)
tc->pan_oy = w->sy - tty->osy;
c->pan_oy += adjust;
if (c->pan_oy > w->sy - tty->osy)
c->pan_oy = w->sy - tty->osy;
}
}
tty_update_client_offset(tc);
server_redraw_client(tc);
tty_update_client_offset(c);
server_redraw_client(c);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l'))
return (cmd_refresh_client_clipboard(self, item));
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'F')) /* -F is an alias for -f */
server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'r'))
cmd_refresh_report(tty, args_get(args, 'r'));
if (args_has(args, 'A')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
av = args_first_value(args, 'A');
while (av != NULL) {
cmd_refresh_client_update_offset(tc, av->string);
av = args_next_value(av);
if (args_has(args, 'C') || args_has(args, 'F')) {
if (args_has(args, 'C')) {
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
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(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
}
if (args_has(args, 'F')) {
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
s = copy = xstrdup(args_get(args, 'F'));
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
c->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'B')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
av = args_first_value(args, 'B');
while (av != NULL) {
cmd_refresh_client_update_subscription(tc, av->string);
av = args_next_value(av);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'C')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
return (cmd_refresh_client_control_client_size(self, item));
}
if (args_has(args, 'S')) {
tc->flags |= CLIENT_STATUSFORCE;
server_status_client(tc);
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
tc->flags |= CLIENT_STATUSFORCE;
server_redraw_client(tc);
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
return (CMD_RETURN_NORMAL);
not_control_client:
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}

View File

@ -34,7 +34,7 @@ const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session",
.alias = "rename",
.args = { "t:", 1, 1, NULL },
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name",
.target = { 't', CMD_FIND_SESSION, 0 },
@ -46,23 +46,22 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
char *newname, *tmp;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
char *newname;
tmp = format_single_from_target(item, args_string(args, 0));
newname = session_check_name(tmp);
if (newname == NULL) {
cmdq_error(item, "invalid session: %s", tmp);
free(tmp);
return (CMD_RETURN_ERROR);
}
free(tmp);
newname = format_single(item, args->argv[0], c, s, NULL, NULL);
if (strcmp(newname, s->name) == 0) {
free(newname);
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) {
cmdq_error(item, "duplicate session: %s", newname);
free(newname);

View File

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

View File

@ -19,7 +19,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@ -36,8 +35,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane",
.alias = "resizep",
.args = { "DLMRTt:Ux:y:Z", 0, 1, NULL },
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
.args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -49,56 +48,43 @@ const struct cmd_entry cmd_resize_pane_entry = {
static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct window_pane *wp = target->wp;
struct winlink *wl = target->wl;
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct client *c = cmdq_get_client(item);
struct session *s = target->s;
struct client *c = item->client;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust;
int x, y, status;
struct grid *gd = wp->base.grid;
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);
}
int x, y;
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);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
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);
}
if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w, 1);
window_unzoom(w);
else
window_zoom(wp);
server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
if (args_count(args) == 0)
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr);
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
@ -106,7 +92,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'x')) {
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause);
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
@ -115,23 +101,12 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(args, 'y')) {
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause);
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);
}
status = options_get_number(w->options, "pane-border-status");
switch (status) {
case PANE_STATUS_TOP:
if (y != INT_MAX && wp->yoff == 1)
y++;
break;
case PANE_STATUS_BOTTOM:
if (y != INT_MAX && wp->yoff + wp->sy == w->sy - 1)
y++;
break;
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_resize_window_entry = {
.name = "resize-window",
.alias = "resizew",
.args = { "aADLRt:Ux:y:", 0, 1, NULL },
.args = { "aADLRt:Ux:y:", 0, 1 },
.usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " "
"[adjustment]",
@ -46,19 +46,18 @@ const struct cmd_entry cmd_resize_window_entry = {
static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = target->s;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust, sx, sy, xpixel = 0, ypixel = 0;
u_int adjust, sx, sy;
if (args_count(args) == 0)
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr);
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
@ -98,18 +97,13 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
} else if (args_has(args, 'D'))
sy += adjust;
if (args_has(args, 'A')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_LARGEST);
} else if (args_has(args, 'a')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_SMALLEST);
}
if (args_has(args, 'A'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST);
else if (args_has(args, 'a'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST);
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
w->manual_sx = sx;
w->manual_sy = sy;
recalculate_size(w, 1);
resize_window(w, sx, sy);
return (CMD_RETURN_NORMAL);
}

View File

@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
.args = { "c:e:kt:", 0, -1, NULL },
.args = { "c:e:kt:", 0, -1 },
.usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -47,28 +47,32 @@ const struct cmd_entry cmd_respawn_pane_entry = {
static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc = { 0 };
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct args *args = self->args;
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
char *cause = NULL;
struct args_value *av;
const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.wp0 = wp;
sc.lc = NULL;
args_to_vector(args, &sc.argc, &sc.argv);
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(sc.environ, av->string, 0);
av = args_next_value(av);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = -1;
@ -81,18 +85,12 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
if (spawn_pane(&sc, &cause) == NULL) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}

View File

@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
.args = { "c:e:kt:", 0, -1, NULL },
.args = { "c:e:kt:", 0, -1 },
.usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]",
CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -47,27 +47,28 @@ const struct cmd_entry cmd_respawn_window_entry = {
static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc = { 0 };
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct args *args = self->args;
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cause = NULL;
struct args_value *av;
const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.tc = tc;
args_to_vector(args, &sc.argc, &sc.argv);
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(sc.environ, av->string, 0);
av = args_next_value(av);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = -1;
@ -80,16 +81,11 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
if (spawn_window(&sc, &cause) == NULL) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
}
server_redraw_window(wl->window);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}

View File

@ -31,8 +31,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window",
.alias = "rotatew",
.args = { "Dt:UZ", 0, 0, NULL },
.usage = "[-DUZ] " CMD_TARGET_WINDOW_USAGE,
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -43,18 +43,16 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
window_push_zoom(w, 0, args_has(args, 'Z'));
server_unzoom_window(w);
if (args_has(args, 'D')) {
if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
@ -79,6 +77,9 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
@ -104,12 +105,10 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
window_pop_zoom(w);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@ -20,7 +20,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@ -30,12 +29,8 @@
* Runs a command without a window.
*/
static enum args_parse_type cmd_run_shell_args_parse(struct args *, u_int,
char **);
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_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
@ -44,9 +39,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
.args = { "bd:Ct:Es:c:", 0, 1, cmd_run_shell_args_parse },
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
" [shell-command]",
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -55,26 +49,11 @@ const struct cmd_entry cmd_run_shell_entry = {
};
struct cmd_run_shell_data {
struct client *client;
char *cmd;
struct args_command_state *state;
char *cwd;
struct cmdq_item *item;
struct session *s;
int wp_id;
struct event timer;
int flags;
char *cmd;
struct cmdq_item *item;
int wp_id;
};
static enum args_parse_type
cmd_run_shell_args_parse(struct args *args, __unused u_int idx,
__unused char **cause)
{
if (args_has(args, 'C'))
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static void
cmd_run_shell_print(struct job *job, const char *msg)
{
@ -90,153 +69,63 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg);
return;
}
if (cdata->item != NULL && cdata->client != NULL)
wp = server_client_get_pane(cdata->client);
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
wp = fs.wp;
if (cmd_find_from_nothing(&fs, 0) != 0)
return;
wp = fs.wp;
if (wp == NULL)
return;
}
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
window_copy_add(wp, 1, "%s", msg);
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct window_pane *wp = target->wp;
const char *delay, *cmd;
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_count(args) == 0)
return (CMD_RETURN_NORMAL);
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;
cdata = xcalloc(1, sizeof *cdata);
if (!args_has(args, 'C')) {
cmd = args_string(args, 0);
if (cmd != NULL)
cdata->cmd = format_single_from_target(item, cmd);
} else {
cdata->state = args_make_commands_prepare(self, item, 0, NULL,
wait, 1);
}
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (wait) {
cdata->client = c;
if (!args_has(args, 'b'))
cdata->item = item;
} else {
cdata->client = tc;
cdata->flags |= JOB_NOWAIT;
if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
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++;
if (args_has(args, 'c'))
cdata->cwd = xstrdup(args_get(args, 'c'));
else
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
if (args_has(args, 'E'))
cdata->flags |= JOB_SHOWSTDERR;
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)
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
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;
struct cmdq_item *item = cdata->item, *new_item;
struct cmd_list *cmdlist;
char *error;
if (cdata->state == NULL) {
if (cmd == NULL) {
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
return;
}
if (job_run(cmd, 0, NULL, 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;
}
cmdlist = args_make_commands(cdata->state, 0, NULL, &error);
if (cmdlist == NULL) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);
} else if (item == NULL) {
new_item = cmdq_get_command(cmdlist, NULL);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item);
}
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
}
static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job);
struct cmdq_item *item = cdata->item;
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size;
int retcode, status;
do {
line = evbuffer_readln(event->input, NULL, EVBUFFER_EOL_LF);
if (line != NULL) {
if ((line = evbuffer_readline(event->input)) != NULL) {
cmd_run_shell_print(job, line);
free(line);
}
@ -260,19 +149,13 @@ cmd_run_shell_callback(struct job *job)
} else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
retcode += 128;
} else
retcode = 0;
}
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
if (item != NULL) {
if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
if (cdata->item != NULL)
cmdq_continue(cdata->item);
}
static void
@ -280,14 +163,6 @@ cmd_run_shell_free(void *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);
if (cdata->state != NULL)
args_make_commands_free(cdata->state);
free(cdata->cwd);
free(cdata->cmd);
free(cdata);
}

View File

@ -37,7 +37,7 @@ const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer",
.alias = "saveb",
.args = { "ab:", 1, 1, NULL },
.args = { "ab:", 1, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK,
@ -48,45 +48,34 @@ const struct cmd_entry cmd_show_buffer_entry = {
.name = "show-buffer",
.alias = "showb",
.args = { "b:", 0, 0, NULL },
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec
};
static void
cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
__unused int closed, __unused struct evbuffer *buffer, void *data)
{
struct cmdq_item *item = data;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
cmdq_continue(item);
}
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct args *args = self->args;
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;
int flags;
const char *bufname = args_get(args, 'b'), *bufdata;
size_t bufsize;
char *path;
struct evbuffer *evb;
const char *bufname, *bufdata, *start, *end, *flags;
char *msg, *path, *file;
size_t size, used, msglen, bufsize;
FILE *f;
if (bufname == NULL) {
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(item, "no buffers");
return (CMD_RETURN_ERROR);
}
} else {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname);
@ -95,26 +84,78 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
}
bufdata = paste_buffer_data(pb, &bufsize);
if (cmd_get_entry(self) == &cmd_show_buffer_entry) {
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
evb = evbuffer_new();
if (evb == NULL)
fatalx("out of memory");
evbuffer_add(evb, bufdata, bufsize);
cmdq_print_data(item, evb);
evbuffer_free(evb);
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_show_buffer_entry)
path = xstrdup("-");
} else
path = format_single_from_target(item, args_string(args, 0));
if (args_has(args, 'a'))
flags = O_APPEND;
else
flags = O_TRUNC;
file_write(cmdq_get_client(item), path, flags, bufdata, bufsize,
cmd_save_buffer_done, item);
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
if (c == NULL) {
cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
flags = "wb";
if (args_has(self->args, 'a'))
flags = "ab";
file = server_client_get_path(item->client, path);
free(path);
return (CMD_RETURN_WAIT);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}
fclose(f);
free(file);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, bufdata, bufsize);
server_client_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(item, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != bufsize) {
start = bufdata + used;
end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(item, "%s", msg);
used += size + (end != NULL);
}
free(msg);
return (CMD_RETURN_NORMAL);
}

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout",
.alias = "selectl",
.args = { "Enopt:", 0, 1, NULL },
.args = { "Enopt:", 0, 1 },
.usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -46,7 +46,7 @@ const struct cmd_entry cmd_next_layout_entry = {
.name = "next-layout",
.alias = "nextl",
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -59,7 +59,7 @@ const struct cmd_entry cmd_previous_layout_entry = {
.name = "previous-layout",
.alias = "prevl",
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -71,21 +71,20 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp = target->wp;
struct window_pane *wp = item->target.wp;
const char *layoutname;
char *oldlayout, *cause;
char *oldlayout;
int next, previous, layout;
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'))
next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_layout_entry);
previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p'))
previous = 1;
@ -105,28 +104,27 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
goto changed;
}
if (args_count(args) != 0)
layoutname = args_string(args, 0);
else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (!args_has(args, 'o')) {
if (layoutname == NULL)
if (args->argc == 0)
layout = w->lastlayout;
else
layout = layout_set_lookup(layoutname);
layout = layout_set_lookup(args->argv[0]);
if (layout != -1) {
layout_set_select(w, layout);
goto changed;
}
}
if (args->argc != 0)
layoutname = args->argv[0];
else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (layoutname != NULL) {
if (layout_parse(w, layoutname, &cause) == -1) {
cmdq_error(item, "%s: %s", cause, layoutname);
free(cause);
if (layout_parse(w, layoutname) == -1) {
cmdq_error(item, "can't set layout: %s", layoutname);
goto error;
}
goto changed;

View File

@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:RT:t:UZ", 0, 0, NULL }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:RT:t:U", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRU] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -46,8 +46,8 @@ const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane",
.alias = "lastp",
.args = { "det:Z", 0, 0, NULL },
.usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE,
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -83,26 +83,20 @@ cmd_select_pane_redraw(struct window *w)
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const struct cmd_entry *entry = cmd_get_entry(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct winlink *wl = target->wl;
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = target->s;
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
struct options *oo = wp->options;
char *title;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
char *pane_title;
const char *style;
struct style *sy;
struct options_entry *o;
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
/*
* Check for no last pane found in case the other pane was
* spawned without being visited (for example split-window -d).
*/
lastwp = TAILQ_FIRST(&w->last_panes);
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL)
@ -112,24 +106,17 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'e')) {
if (args_has(self->args, 'e'))
lastwp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
} else if (args_has(args, 'd')) {
else if (args_has(self->args, 'd'))
lastwp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
} else {
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w);
else {
server_unzoom_window(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
if (window_pop_zoom(w))
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
}
@ -137,10 +124,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') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL);
if (server_check_marked())
lastwp = marked_pane.wp;
else
lastwp = NULL;
lastwp = marked_pane.wp;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
@ -149,96 +133,78 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
markedwp = marked_pane.wp;
if (lastwp != NULL) {
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
return (CMD_RETURN_NORMAL);
}
style = args_get(args, 'P');
if (style != NULL) {
o = options_set_string(oo, "window-style", 0, "%s", style);
if (o == NULL) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if ((style = args_get(args, 'P')) != NULL) {
o = options_set_style(wp->options, "window-style", 0,
style);
if (o == NULL) {
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|PANE_THEMECHANGED);
}
if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'L')) {
window_push_zoom(w, 0, 1);
if (args_has(self->args, 'L')) {
server_unzoom_window(wp->window);
wp = window_pane_find_left(wp);
window_pop_zoom(w);
} else if (args_has(args, 'R')) {
window_push_zoom(w, 0, 1);
} else if (args_has(self->args, 'R')) {
server_unzoom_window(wp->window);
wp = window_pane_find_right(wp);
window_pop_zoom(w);
} else if (args_has(args, 'U')) {
window_push_zoom(w, 0, 1);
} else if (args_has(self->args, 'U')) {
server_unzoom_window(wp->window);
wp = window_pane_find_up(wp);
window_pop_zoom(w);
} else if (args_has(args, 'D')) {
window_push_zoom(w, 0, 1);
} else if (args_has(self->args, 'D')) {
server_unzoom_window(wp->window);
wp = window_pane_find_down(wp);
window_pop_zoom(w);
}
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'e')) {
if (args_has(self->args, 'e')) {
wp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'd')) {
if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'T')) {
pane_title = format_single(item, args_get(self->args, 'T'),
c, s, wl, wp);
screen_set_title(&wp->base, pane_title);
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'T')) {
title = format_single_from_target(item, args_get(args, 'T'));
if (screen_set_title(&wp->base, title)) {
notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
}
free(title);
if (wp == w->active)
return (CMD_RETURN_NORMAL);
}
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
activewp = server_client_get_pane(c);
else
activewp = w->active;
if (wp == activewp)
return (CMD_RETURN_NORMAL);
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w);
server_unzoom_window(wp->window);
window_redraw_active_switch(w, wp);
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
server_client_set_pane(c, wp);
else if (window_set_active_pane(w, wp, 1))
if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
if (window_pop_zoom(w))
server_redraw_window(w);
cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_window_entry = {
.name = "select-window",
.alias = "selectw",
.args = { "lnpTt:", 0, 0, NULL },
.args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -46,7 +46,7 @@ const struct cmd_entry cmd_next_window_entry = {
.name = "next-window",
.alias = "next",
.args = { "at:", 0, 0, NULL },
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -59,7 +59,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.name = "previous-window",
.alias = "prev",
.args = { "at:", 0, 0, NULL },
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -72,7 +72,7 @@ const struct cmd_entry cmd_last_window_entry = {
.name = "last-window",
.alias = "last",
.args = { "t:", 0, 0, NULL },
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@ -84,26 +84,23 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct session *s = target->s;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct session *s = item->target.s;
int next, previous, last, activity;
next = (cmd_get_entry(self) == &cmd_next_window_entry);
if (args_has(args, 'n'))
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_window_entry);
if (args_has(args, 'p'))
previous = self->entry == &cmd_previous_window_entry;
if (args_has(self->args, 'p'))
previous = 1;
last = (cmd_get_entry(self) == &cmd_last_window_entry);
if (args_has(args, 'l'))
last = self->entry == &cmd_last_window_entry;
if (args_has(self->args, 'l'))
last = 1;
if (next || previous || last) {
activity = args_has(args, 'a');
activity = args_has(self->args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
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
* 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) {
cmdq_error(item, "no last window");
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");
}
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@ -33,13 +33,12 @@ const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys",
.alias = "send",
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
CMD_TARGET_PANE_USAGE " [key ...]",
.args = { "HlXRMN:t:", 0, -1 },
.usage = "[-HlXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
};
@ -47,7 +46,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
.name = "send-prefix",
.alias = NULL,
.args = { "2t:", 0, 0, NULL },
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -57,56 +56,38 @@ const struct cmd_entry cmd_send_prefix_entry = {
};
static struct cmdq_item *
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
struct args *args, key_code key)
cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key)
{
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct window_mode_entry *wme;
struct key_table *table = NULL;
struct key_table *table;
struct key_binding *bd;
struct key_event *event;
if (args_has(args, 'K')) {
if (tc == NULL)
return (item);
event = xcalloc(1, sizeof *event);
event->key = key|KEYC_SENT;
memset(&event->m, 0, sizeof event->m);
if (server_client_handle_key(tc, event) == 0) {
free(event->buf);
free(event);
}
return (item);
}
wme = TAILQ_FIRST(&wp->modes);
wme = TAILQ_FIRST(&fs->wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) {
if (window_pane_key(wp, tc, s, wl, key, NULL) != 0)
return (NULL);
if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL);
return (item);
}
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) {
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);
}
return (after);
return (item);
}
static struct cmdq_item *
cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
struct args *args, int i)
cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, struct args *args, int i)
{
const char *s = args_string(args, i);
struct utf8_data *ud, *loop;
utf8_char uc;
const char *s = args->argv[i];
struct utf8_data *ud, *uc;
wchar_t wc;
key_code key;
char *endptr;
long n;
@ -116,67 +97,53 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item);
return (cmd_send_keys_inject_key(item, after, args,
KEYC_LITERAL|n));
return (cmd_send_keys_inject_key(c, fs, item, KEYC_LITERAL|n));
}
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
after = cmd_send_keys_inject_key(item, after, args,
key);
if (after != NULL)
return (after);
}
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
return (cmd_send_keys_inject_key(c, fs, item, key));
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(s);
for (loop = ud; loop->size != 0; loop++) {
if (loop->size == 1 && loop->data[0] <= 0x7f)
key = loop->data[0];
else {
if (utf8_from_data(loop, &uc) != UTF8_DONE)
continue;
key = uc;
}
after = cmd_send_keys_inject_key(item, after, args,
key);
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
item = cmd_send_keys_inject_key(c, fs, item, wc);
}
free(ud);
}
return (after);
return (item);
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct key_event *event = cmdq_get_event(item);
struct mouse_event *m = &event->m;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *fs = &item->target;
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct mouse_event *m = &item->shared->mouse;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct cmdq_item *after = item;
int i;
key_code key;
u_int i, np = 1;
u_int count = args_count(args);
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) {
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item,
&cause);
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (wme != NULL && (args_has(args, 'X') || count == 0)) {
if (wme->mode->command == NULL) {
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
@ -191,7 +158,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
}
if (!m->valid)
m = NULL;
wme->mode->command(wme, tc, s, wl, args, m);
wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
@ -201,38 +168,27 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target");
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);
}
if (cmd_get_entry(self) == &cmd_send_prefix_entry) {
if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
cmd_send_keys_inject_key(item, item, args, key);
cmd_send_keys_inject_key(c, fs, item, key);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R')) {
colour_palette_clear(&wp->palette);
input_reset(wp->ictx, 1);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW);
}
if (count == 0) {
if (args_has(args, 'N') || args_has(args, 'R'))
return (CMD_RETURN_NORMAL);
for (; np != 0; np--)
cmd_send_keys_inject_key(item, NULL, args, event->key);
return (CMD_RETURN_NORMAL);
window_pane_reset_palette(wp);
input_reset(wp, 1);
}
for (; np != 0; np--) {
for (i = 0; i < count; i++) {
after = cmd_send_keys_inject_string(item, after, args,
i);
}
for (i = 0; i < args->argc; i++)
item = cmd_send_keys_inject_string(c, fs, item, args, i);
}
return (CMD_RETURN_NORMAL);

View File

@ -1,147 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 Dallas Lyons <dallasdlyons@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/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Controls access to session.
*/
static enum cmd_retval cmd_server_access_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_server_access_entry = {
.name = "server-access",
.alias = NULL,
.args = { "adlrw", 0, 1, NULL },
.usage = "[-adlrw] " CMD_TARGET_PANE_USAGE " [user]",
.flags = CMD_CLIENT_CANFAIL,
.exec = cmd_server_access_exec
};
static enum cmd_retval
cmd_server_access_deny(struct cmdq_item *item, struct passwd *pw)
{
struct client *loop;
struct server_acl_user *user;
uid_t uid;
if ((user = server_acl_user_find(pw->pw_uid)) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
TAILQ_FOREACH(loop, &clients, entry) {
uid = proc_get_peer_uid(loop->peer);
if (uid == server_acl_get_uid(user)) {
loop->exit_message = xstrdup("access not allowed");
loop->flags |= CLIENT_EXIT;
}
}
server_acl_user_deny(pw->pw_uid);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_target_client(item);
char *name;
struct passwd *pw = NULL;
if (args_has(args, 'l')) {
server_acl_display(item);
return (CMD_RETURN_NORMAL);
}
if (args_count(args) == 0) {
cmdq_error(item, "missing user argument");
return (CMD_RETURN_ERROR);
}
name = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
if (*name != '\0')
pw = getpwnam(name);
if (pw == NULL) {
cmdq_error(item, "unknown user: %s", name);
return (CMD_RETURN_ERROR);
}
free(name);
if (pw->pw_uid == 0 || pw->pw_uid == getuid()) {
cmdq_error(item, "%s owns the server, can't change access",
pw->pw_name);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'a') && args_has(args, 'd')) {
cmdq_error(item, "-a and -d cannot be used together");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'w') && args_has(args, 'r')) {
cmdq_error(item, "-r and -w cannot be used together");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'd'))
return (cmd_server_access_deny(item, pw));
if (args_has(args, 'a')) {
if (server_acl_user_find(pw->pw_uid) != NULL) {
cmdq_error(item, "user %s is already added",
pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_allow(pw->pw_uid);
/* Do not return - allow -r or -w with -a. */
} else if (args_has(args, 'r') || args_has(args, 'w')) {
/* -r or -w implies -a if user does not exist. */
if (server_acl_user_find(pw->pw_uid) == NULL)
server_acl_user_allow(pw->pw_uid);
}
if (args_has(args, 'w')) {
if (server_acl_user_find(pw->pw_uid) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_allow_write(pw->pw_uid);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'r')) {
if (server_acl_user_find(pw->pw_uid) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_deny_write(pw->pw_uid);
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",
.alias = "setb",
.args = { "ab:t:n:w", 0, 1, NULL },
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
CMD_TARGET_CLIENT_USAGE " [data]",
.args = { "ab:n:", 0, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
.flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec
};
@ -45,7 +44,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
.name = "delete-buffer",
.alias = "deleteb",
.args = { "b:", 0, 0, NULL },
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
@ -55,8 +54,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct args *args = self->args;
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
@ -68,14 +66,9 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
else
pb = paste_get_name(bufname);
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
if (pb == NULL) {
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
}
if (self->entry == &cmd_delete_buffer_entry) {
if (pb == NULL)
pb = paste_get_top(&bufname);
}
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
@ -85,13 +78,8 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'n')) {
if (pb == NULL) {
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
}
if (pb == NULL)
pb = paste_get_top(&bufname);
}
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
@ -104,11 +92,11 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_count(args) != 1) {
if (args->argc != 1) {
cmdq_error(item, "no data specified");
return (CMD_RETURN_ERROR);
}
if ((newsize = strlen(args_string(args, 0))) == 0)
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
bufsize = 0;
@ -121,7 +109,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
}
bufdata = xrealloc(bufdata, bufsize + newsize);
memcpy(bufdata + bufsize, args_string(args, 0), newsize);
memcpy(bufdata + bufsize, args->argv[0], newsize);
bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
@ -130,8 +118,6 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, "", bufdata, bufsize);
return (CMD_RETURN_NORMAL);
}

View File

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

View File

@ -18,6 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
@ -27,17 +28,23 @@
* Set an option.
*/
static enum args_parse_type cmd_set_option_args_parse(struct args *,
u_int, char **);
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 = {
.name = "set-option",
.alias = "set",
.args = { "aFgopqst:uUw", 1, 2, cmd_set_option_args_parse },
.usage = "[-aFgopqsuUw] " CMD_TARGET_PANE_USAGE " option [value]",
.args = { "aFgopqst:uw", 1, 2 },
.usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -49,7 +56,7 @@ const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option",
.alias = "setw",
.args = { "aFgoqt:u", 1, 2, cmd_set_option_args_parse },
.args = { "aFgoqt:u", 1, 2 },
.usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
@ -62,46 +69,41 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "agpRt:uw", 1, 2, cmd_set_option_args_parse },
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
.args = { "agRt:u", 1, 2 },
.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,
.exec = cmd_set_option_exec
};
static enum args_parse_type
cmd_set_option_args_parse(__unused struct args *args, u_int idx,
__unused char **cause)
{
if (idx == 1)
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static enum cmd_retval
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');
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *loop;
struct cmd_find_state *fs = &item->target;
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_entry *parent, *o, *po;
char *name, *argument, *expanded = NULL;
char *cause;
const char *value;
struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause;
int window, idx, already, error, ambiguous;
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. */
argument = format_single_from_target(item, args_string(args, 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 (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);
free(argument);
return (CMD_RETURN_NORMAL);
@ -118,18 +120,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
if (args_count(args) < 2)
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else
value = args_string(args, 1);
if (value != NULL && args_has(args, 'F')) {
expanded = format_single_from_target(item, value);
value = expanded;
}
value = xstrdup(args->argv[1]);
/* Get the scope and table for the option .*/
scope = options_scope_from_name(args, window, name, target, &oo,
&cause);
scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
@ -141,7 +140,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name);
/* 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);
goto fail;
}
@ -165,22 +164,19 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
/* Change the option. */
if (args_has(args, 'U') && scope == OPTIONS_TABLE_WINDOW) {
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 (args_has(args, 'u')) {
if (o == NULL)
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);
free(cause);
goto fail;
@ -191,15 +187,10 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_is_array(parent)) {
error = options_from_string(oo, options_table_entry(parent),
options_table_entry(parent)->name, value,
args_has(args, 'a'), &cause);
if (error != 0) {
cmdq_error(item, "%s", cause);
free(cause);
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
goto fail;
}
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
@ -223,17 +214,198 @@ 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:
free(argument);
free(expanded);
free(value);
free(name);
return (CMD_RETURN_NORMAL);
fail:
free(argument);
free(expanded);
free(value);
free(name);
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",
.alias = "showenv",
.args = { "hgst:", 0, 1, NULL },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [variable]",
.args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.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,
struct environ_entry *envent)
{
struct args *args = cmd_get_args(self);
char *escaped;
char *escaped;
if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN))
return;
if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
return;
if (!args_has(args, 's')) {
if (!args_has(self->args, 's')) {
if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value);
else
@ -97,37 +91,36 @@ cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct args *args = self->args;
struct environ *env;
struct environ_entry *envent;
const char *tflag, *name = args_string(args, 0);
const char *target;
if ((tflag = args_get(args, 't')) != NULL) {
if (target->s == NULL) {
cmdq_error(item, "no such session: %s", tflag);
if ((target = args_get(args, 't')) != NULL) {
if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'g'))
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (target->s == NULL) {
tflag = args_get(args, 't');
if (tflag != NULL)
cmdq_error(item, "no such session: %s", tflag);
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = target->s->environ;
env = item->target.s->environ;
}
if (name != NULL) {
envent = environ_find(env, name);
if (args->argc != 0) {
envent = environ_find(env, args->argv[0]);
if (envent == NULL) {
cmdq_error(item, "unknown variable: %s", name);
cmdq_error(item, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
cmd_show_environment_print(self, item, envent);

View File

@ -18,19 +18,16 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.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 *,
struct cmdq_item *);
@ -38,31 +35,29 @@ const struct cmd_entry cmd_show_messages_entry = {
.name = "show-messages",
.alias = "showmsgs",
.args = { "JTt:", 0, 0, NULL },
.args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec
};
static int cmd_show_messages_terminals(struct cmdq_item *, 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;
u_int i, n;
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
if (args_has(args, 't') && term != tc->tty.term)
continue;
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n,
term->name, term->tty->client->name, term->flags);
cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags);
n++;
for (i = 0; i < tty_term_ncodes(); 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
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;
char *s;
char *tim;
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;
if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(self, item, blank);
blank = cmd_show_messages_terminals(item, blank);
done = 1;
}
if (args_has(args, 'J')) {
@ -91,17 +89,12 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
if (done)
return (CMD_RETURN_NORMAL);
ft = format_create_from_target(item);
TAILQ_FOREACH_REVERSE(msg, &message_log, message_list, entry) {
format_add(ft, "message_text", "%s", msg->msg);
format_add(ft, "message_number", "%u", msg->msg_num);
format_add_tv(ft, "message_time", &msg->msg_time);
TAILQ_FOREACH(msg, &c->message_log, entry) {
tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0';
s = format_expand(ft, SHOW_MESSAGES_TEMPLATE);
cmdq_print(item, "%s", s);
free(s);
cmdq_print(item, "%s %s", tim, msg->msg);
}
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@ -38,7 +38,7 @@ const struct cmd_entry cmd_show_options_entry = {
.name = "show-options",
.alias = "show",
.args = { "AgHpqst:vw", 0, 1, NULL },
.args = { "AgHpqst:vw", 0, 1 },
.usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -51,7 +51,7 @@ const struct cmd_entry cmd_show_window_options_entry = {
.name = "show-window-options",
.alias = "showw",
.args = { "gvt:", 0, 1, NULL },
.args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
@ -64,10 +64,10 @@ const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gpt:w", 0, 1, NULL },
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@ -76,18 +76,20 @@ const struct cmd_entry cmd_show_hooks_entry = {
static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct args *args = self->args;
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;
char *argument, *name = NULL, *cause;
int window, idx, ambiguous, parent, scope;
struct options_entry *o;
window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
window = (self->entry == &cmd_show_window_options_entry);
if (args_count(args) == 0) {
scope = options_scope_from_flags(args, window, target, &oo,
&cause);
if (args->argc == 0) {
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
@ -97,23 +99,22 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
}
return (cmd_show_options_all(self, item, scope, oo));
}
argument = format_single_from_target(item, args_string(args, 0));
argument = format_single(item, args->argv[0], c, s, wl, NULL);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
goto out;
goto fail;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
scope = options_scope_from_name(args, window, name, target, &oo,
&cause);
scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
goto fail;
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
@ -126,14 +127,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
parent = 0;
if (o != NULL)
cmd_show_options_print(self, item, o, idx, parent);
else if (*name == '@') {
if (args_has(args, 'q'))
goto out;
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
out:
free(name);
free(argument);
return (CMD_RETURN_NORMAL);
@ -148,7 +142,6 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx, int parent)
{
struct args *args = cmd_get_args(self);
struct options_array_item *a;
const char *name = options_name(o);
char *value, *tmp = NULL, *escaped;
@ -157,10 +150,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_is_array(o)) {
if (options_isarray(o)) {
a = options_array_first(o);
if (a == NULL) {
if (!args_has(args, 'v'))
if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", name);
return;
}
@ -174,10 +167,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
}
value = options_to_string(o, idx, 0);
if (args_has(args, 'v'))
value = options_tostring(o, idx, 0);
if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value);
else if (options_is_string(o)) {
else if (options_isstring(o)) {
escaped = args_escape(value);
if (parent)
cmdq_print(item, "%s* %s", name, escaped);
@ -199,7 +192,6 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo)
{
struct args *args = cmd_get_args(self);
const struct options_table_entry *oe;
struct options_entry *o;
struct options_array_item *a;
@ -207,28 +199,28 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
u_int idx;
int parent;
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
o = options_first(oo);
while (o != NULL) {
if (options_table_entry(o) == NULL)
cmd_show_options_print(self, item, o, -1, 0);
o = options_next(o);
}
o = options_first(oo);
while (o != NULL) {
if (options_table_entry(o) == NULL)
cmd_show_options_print(self, item, o, -1, 0);
o = options_next(o);
}
for (oe = options_table; oe->name != NULL; oe++) {
if (~oe->scope & scope)
continue;
if ((cmd_get_entry(self) != &cmd_show_hooks_entry &&
!args_has(args, 'H') &&
if ((self->entry != &cmd_show_hooks_entry &&
!args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(cmd_get_entry(self) == &cmd_show_hooks_entry &&
(~oe->flags & OPTIONS_TABLE_IS_HOOK)))
(self->entry == &cmd_show_hooks_entry &&
(oe == NULL ||
(~oe->flags & OPTIONS_TABLE_IS_HOOK))))
continue;
o = options_get_only(oo, oe->name);
if (o == NULL) {
if (!args_has(args, 'A'))
if (!args_has(self->args, 'A'))
continue;
o = options_get(oo, oe->name);
if (o == NULL)
@ -237,10 +229,10 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
} else
parent = 0;
if (!options_is_array(o))
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
if (!args_has(args, 'v')) {
if (!args_has(self->args, 'v')) {
name = options_name(o);
if (parent)
cmdq_print(item, "%s*", name);

View File

@ -1,108 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 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 <stdlib.h>
/*
* Show or clear prompt history.
*/
static enum cmd_retval cmd_show_prompt_history_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_show_prompt_history_entry = {
.name = "show-prompt-history",
.alias = "showphist",
.args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]",
.flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec
};
const struct cmd_entry cmd_clear_prompt_history_entry = {
.name = "clear-prompt-history",
.alias = "clearphist",
.args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]",
.flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec
};
static enum cmd_retval
cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const char *typestr = args_get(args, 'T');
enum prompt_type type;
u_int tidx, hidx;
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
if (typestr == NULL) {
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
free(status_prompt_hlist[tidx]);
status_prompt_hlist[tidx] = NULL;
status_prompt_hsize[tidx] = 0;
}
} else {
type = status_prompt_type(typestr);
if (type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "invalid type: %s", typestr);
return (CMD_RETURN_ERROR);
}
free(status_prompt_hlist[type]);
status_prompt_hlist[type] = NULL;
status_prompt_hsize[type] = 0;
}
return (CMD_RETURN_NORMAL);
}
if (typestr == NULL) {
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
cmdq_print(item, "History for %s:\n",
status_prompt_type_string(tidx));
for (hidx = 0; hidx < status_prompt_hsize[tidx];
hidx++) {
cmdq_print(item, "%d: %s", hidx + 1,
status_prompt_hlist[tidx][hidx]);
}
cmdq_print(item, "%s", "");
}
} else {
type = status_prompt_type(typestr);
if (type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "invalid type: %s", typestr);
return (CMD_RETURN_ERROR);
}
cmdq_print(item, "History for %s:\n",
status_prompt_type_string(type));
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
cmdq_print(item, "%d: %s", hidx + 1,
status_prompt_hlist[type][hidx]);
}
cmdq_print(item, "%s", "");
}
return (CMD_RETURN_NORMAL);
}

View File

@ -29,218 +29,87 @@
* Sources a configuration file.
*/
#define CMD_SOURCE_FILE_DEPTH_LIMIT 50
static u_int cmd_source_file_depth;
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_source_file_done(struct cmdq_item *, void *);
const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
.args = { "t:Fnqv", 1, -1, NULL },
.usage = "[-Fnqv] " CMD_TARGET_PANE_USAGE " path ...",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.args = { "nqv", 1, -1 },
.usage = "[-nqv] path ...",
.flags = 0,
.exec = cmd_source_file_exec
};
struct cmd_source_file_data {
struct cmdq_item *item;
int flags;
struct cmdq_item *after;
enum cmd_retval retval;
u_int current;
char **files;
u_int nfiles;
};
static enum cmd_retval
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
{
struct client *c = cmdq_get_client(item);
if (c == NULL) {
cmd_source_file_depth--;
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
} else {
c->source_file_depth--;
log_debug("%s: depth now %u", __func__, c->source_file_depth);
}
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}
static void
cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
{
struct cmdq_item *new_item;
u_int i;
if (cfg_finished) {
if (cdata->retval == CMD_RETURN_ERROR &&
c != NULL &&
c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
cmdq_insert_after(cdata->after, new_item);
}
for (i = 0; i < cdata->nfiles; i++)
free(cdata->files[i]);
free(cdata->files);
free(cdata);
}
static void
cmd_source_file_done(struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data)
{
struct cmd_source_file_data *cdata = data;
struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer);
u_int n;
struct cmdq_item *new_item;
struct cmd_find_state *target = cmdq_get_target(item);
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) {
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
target, cdata->flags, &new_item) < 0)
cdata->retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
cdata->after = new_item;
}
n = ++cdata->current;
if (n < cdata->nfiles)
file_read(c, cdata->files[n], cmd_source_file_done, cdata);
else {
cmd_source_file_complete(c, cdata);
cmdq_continue(item);
}
}
static void
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
{
char resolved[PATH_MAX];
if (realpath(path, resolved) == NULL) {
log_debug("%s: realpath(\"%s\") failed: %s", __func__,
path, strerror(errno));
} else
path = resolved;
log_debug("%s: %s", __func__, path);
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
sizeof *cdata->files);
cdata->files[cdata->nfiles++] = xstrdup(path);
}
static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_source_file_data *cdata;
struct client *c = cmdq_get_client(item);
enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd, *expanded = NULL;
const char *path, *error;
glob_t g;
int result;
u_int i, j;
if (c == NULL) {
if (cmd_source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
cmdq_error(item, "too many nested files");
return (CMD_RETURN_ERROR);
}
cmd_source_file_depth++;
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
} else {
if (c->source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
cmdq_error(item, "too many nested files");
return (CMD_RETURN_ERROR);
}
c->source_file_depth++;
log_debug("%s: depth now %u", __func__, c->source_file_depth);
}
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
struct args *args = self->args;
int flags = 0;
struct client *c = item->client;
struct cmdq_item *new_item, *after;
enum cmd_retval retval;
char *pattern, *cwd;
const char *path, *error;
glob_t g;
int i;
u_int j;
if (args_has(args, 'q'))
cdata->flags |= CMD_PARSE_QUIET;
flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n'))
cdata->flags |= CMD_PARSE_PARSEONLY;
flags |= CMD_PARSE_PARSEONLY;
if (args_has(args, 'v'))
cdata->flags |= CMD_PARSE_VERBOSE;
flags |= CMD_PARSE_VERBOSE;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
for (i = 0; i < args_count(args); i++) {
path = args_string(args, i);
if (args_has(args, 'F')) {
free(expanded);
expanded = format_single_from_target(item, path);
path = expanded;
}
if (strcmp(path, "-") == 0) {
cmd_source_file_add(cdata, "-");
continue;
}
retval = CMD_RETURN_NORMAL;
for (i = 0; i < args->argc; i++) {
path = args->argv[i];
if (*path == '/')
pattern = xstrdup(path);
else
xasprintf(&pattern, "%s/%s", cwd, path);
log_debug("%s: %s", __func__, pattern);
if ((result = glob(pattern, 0, NULL, &g)) != 0) {
if (result != GLOB_NOMATCH ||
(~cdata->flags & CMD_PARSE_QUIET)) {
if (result == GLOB_NOMATCH)
error = strerror(ENOENT);
else if (result == GLOB_NOSPACE)
error = strerror(ENOMEM);
else
error = strerror(EINVAL);
if (glob(pattern, 0, NULL, &g) != 0) {
error = strerror(errno);
if (errno != ENOENT || (~flags & CMD_PARSE_QUIET)) {
cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR;
}
globfree(&g);
free(pattern);
continue;
}
free(pattern);
for (j = 0; j < g.gl_pathc; j++)
cmd_source_file_add(cdata, g.gl_pathv[j]);
after = item;
for (j = 0; j < g.gl_pathc; j++) {
path = g.gl_pathv[j];
if (load_cfg(path, c, after, flags, &new_item) < 0)
retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
after = new_item;
}
globfree(&g);
}
free(expanded);
cdata->after = item;
cdata->retval = retval;
if (cdata->nfiles != 0) {
file_read(c, cdata->files[0], cmd_source_file_done, cdata);
retval = CMD_RETURN_WAIT;
} else
cmd_source_file_complete(c, cdata);
if (cfg_finished) {
if (retval == CMD_RETURN_ERROR && c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(item, new_item);
}
free(cwd);
return (retval);
}
static enum cmd_retval
cmd_source_file_done(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}

View File

@ -39,10 +39,10 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
" [shell-command [argument ...]]",
.args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
.usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
"[-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE
" [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -53,68 +53,55 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc = { 0 };
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct window_pane *wp = target->wp, *new_wp;
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct spawn_context sc;
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, *new_wp;
enum layout_type type;
struct layout_cell *lc;
struct cmd_find_state fs;
int size, flags, input;
const char *template;
char *cause = NULL, *cp;
struct args_value *av;
u_int count = args_count(args), curval = 0;
int size, percentage, flags, input;
const char *template, *add;
char *cause, *cp;
struct args_value *value;
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
if (args_has(args, 'l') || args_has(args, 'p')) {
if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
curval = w->sy;
else
curval = w->sx;
} else {
if (type == LAYOUT_TOPBOTTOM)
curval = wp->sy;
else
curval = wp->sx;
}
}
size = -1;
else
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause);
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "create pane failed: -l %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause);
if (cause == NULL)
size = curval * size / 100;
}
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "create pane failed: -p %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
} else
size = -1;
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
input = (args_has(args, 'I') && count == 0);
server_unzoom_window(wp->window);
input = (args_has(args, 'I') && args->argc == 0);
flags = 0;
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
if (input || (count == 1 && *args_string(args, 0) == '\0'))
if (input || (args->argc == 1 && *args->argv[0] == '\0'))
flags |= SPAWN_EMPTY;
lc = layout_split_pane(wp, type, size, flags);
@ -123,6 +110,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
@ -130,13 +118,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.wp0 = wp;
sc.lc = lc;
args_to_vector(args, &sc.argc, &sc.argv);
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(sc.environ, av->string, 0);
av = args_next_value(av);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = -1;
@ -145,44 +135,29 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.flags = flags;
if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'Z'))
sc.flags |= SPAWN_ZOOM;
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
layout_close_pane(new_wp);
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
}
if (input) {
switch (window_pane_start_input(new_wp, item, &cause)) {
case -1:
server_client_remove_pane(new_wp);
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
case 1:
input = 0;
break;
}
if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
window_pop_zoom(wp->window);
server_redraw_window(wp->window);
server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
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);
free(cp);
}
@ -190,8 +165,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
cmdq_insert_hook(s, item, &fs, "after-split-window");
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
if (input)
return (CMD_RETURN_WAIT);

View File

@ -32,8 +32,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane",
.alias = "swapp",
.args = { "dDs:t:UZ", 0, 0, NULL },
.usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE,
.args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@ -45,42 +45,32 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
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_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
dst_w = target->wl->window;
dst_wp = target->wp;
src_w = source->wl->window;
src_wp = source->wp;
dst_w = item->target.wl->window;
dst_wp = item->target.wp;
src_w = item->source.wl->window;
src_wp = item->source.wp;
server_unzoom_window(dst_w);
if (window_push_zoom(dst_w, 0, args_has(args, 'Z')))
server_redraw_window(dst_w);
if (args_has(args, 'D')) {
if (args_has(self->args, 'D')) {
src_w = dst_w;
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
} else if (args_has(args, 'U')) {
} else if (args_has(self->args, 'U')) {
src_w = dst_w;
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
}
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z')))
server_redraw_window(src_w);
server_unzoom_window(src_w);
if (src_wp == dst_wp)
goto out;
server_client_remove_pane(src_wp);
server_client_remove_pane(dst_wp);
return (CMD_RETURN_NORMAL);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@ -101,10 +91,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
src_wp->flags |= PANE_STYLECHANGED;
dst_wp->window = src_w;
options_set_parent(dst_wp->options, src_w->options);
dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
dst_wp->flags |= PANE_STYLECHANGED;
sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff;
@ -113,7 +103,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
dst_wp->xoff = xoff; dst_wp->yoff = yoff;
window_pane_resize(dst_wp, sx, sy);
if (!args_has(args, 'd')) {
if (!args_has(self->args, 'd')) {
if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp, 1);
window_set_active_pane(dst_w, src_wp, 1);
@ -128,24 +118,13 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
window_set_active_pane(dst_w, src_wp, 1);
}
if (src_w != dst_w) {
window_pane_stack_remove(&src_w->last_panes, src_wp);
window_pane_stack_remove(&dst_w->last_panes, dst_wp);
colour_palette_from_option(&src_wp->palette, src_wp->options);
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
layout_fix_panes(src_w, NULL);
server_redraw_window(src_w);
if (src_w->last == src_wp)
src_w->last = NULL;
if (dst_w->last == dst_wp)
dst_w->last = NULL;
}
layout_fix_panes(dst_w, NULL);
server_redraw_window(src_w);
server_redraw_window(dst_w);
notify_window("window-layout-changed", src_w);
if (src_w != dst_w)
notify_window("window-layout-changed", dst_w);
out:
if (window_pop_zoom(src_w))
server_redraw_window(src_w);
if (src_w != dst_w && window_pop_zoom(dst_w))
server_redraw_window(dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@ -32,7 +32,7 @@ const struct cmd_entry cmd_swap_window_entry = {
.name = "swap-window",
.alias = "swapw",
.args = { "ds:t:", 0, 0, NULL },
.args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
@ -45,20 +45,20 @@ const struct cmd_entry cmd_swap_window_entry = {
static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
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 *src, *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;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src);
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst);
if (src != dst &&
sg_src != NULL &&
sg_dst != NULL &&
if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src == sg_dst) {
cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR);
@ -77,7 +77,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src->window = w_dst;
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);
if (src != dst)
session_select(src, wl_src->idx);

View File

@ -34,33 +34,33 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client",
.alias = "switchc",
.args = { "lc:EFnpt:rT:Z", 0, 0, NULL },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
.args = { "lc:Enpt:rT:", 0, 0 },
.usage = "[-Elnpr] [-c target-client] [-t target-session] "
"[-T key-table]",
/* -t is special */
.flags = CMD_READONLY|CMD_CLIENT_CFLAG,
.flags = CMD_READONLY,
.exec = cmd_switch_client_exec
};
static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
struct args *args = self->args;
const char *tflag = args_get(args, 't');
enum cmd_find_type type;
int flags;
struct client *tc = cmdq_get_target_client(item);
struct client *c;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
const char *tablename;
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') {
type = CMD_FIND_PANE;
flags = 0;
@ -68,18 +68,14 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
type = CMD_FIND_SESSION;
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);
s = target.s;
wl = target.wl;
wp = target.wp;
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (args_has(args, 'r')) {
if (tc->flags & CLIENT_READONLY)
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY;
tablename = args_get(args, 'T');
if (tablename != NULL) {
@ -89,24 +85,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
table->references++;
key_bindings_unref_table(tc->keytable);
tc->keytable = table;
key_bindings_unref_table(c->keytable);
c->keytable = table;
return (CMD_RETURN_NORMAL);
}
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");
return (CMD_RETURN_ERROR);
}
} 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");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'l')) {
if (tc->last_session != NULL && session_alive(tc->last_session))
s = tc->last_session;
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
else
s = NULL;
if (s == NULL) {
@ -114,29 +110,38 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
} else {
if (cmdq_get_client(item) == NULL)
if (item->client == NULL)
return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) {
w = wl->window;
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
if (window_pop_zoom(w))
server_redraw_window(w);
}
if (wl != NULL) {
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp, 1);
}
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'))
environ_update(s->options, tc->environ, s->environ);
environ_update(s->options, c->environ, s->environ);
server_client_set_session(tc, s);
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(tc, NULL);
if (c->session != NULL && c->session != s)
c->last_session = c->session;
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
recalculate_sizes();
server_check_unattached();
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
alerts_check_session(s);
return (CMD_RETURN_NORMAL);
}

View File

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

View File

@ -34,7 +34,7 @@ const struct cmd_entry cmd_wait_for_entry = {
.name = "wait-for",
.alias = "wait",
.args = { "LSU", 1, 1, NULL },
.args = { "LSU", 1, 1 },
.usage = "[-L|-S|-U] channel",
.flags = 0,
@ -120,12 +120,12 @@ cmd_wait_for_remove(struct wait_channel *wc)
static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const char *name = args_string(args, 0);
struct wait_channel *wc, find;
struct args *args = self->args;
const char *name = args->argv[0];
struct wait_channel *wc, wc0;
find.name = name;
wc = RB_FIND(wait_channels, &wait_channels, &find);
wc0.name = name;
wc = RB_FIND(wait_channels, &wait_channels, &wc0);
if (args_has(args, 'S'))
return (cmd_wait_for_signal(item, name, wc));
@ -167,7 +167,7 @@ static enum cmd_retval
cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc)
{
struct client *c = cmdq_get_client(item);
struct client *c = item->client;
struct wait_item *wi;
if (c == NULL) {
@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{
struct wait_item *wi;
if (cmdq_get_client(item) == NULL) {
if (item->client == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR);
}

297
cmd.c
View File

@ -35,18 +35,16 @@ extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_tree_entry;
extern const struct cmd_entry cmd_clear_history_entry;
extern const struct cmd_entry cmd_clear_prompt_history_entry;
extern const struct cmd_entry cmd_clock_mode_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_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_detach_client_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_popup_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_find_window_entry;
extern const struct cmd_entry cmd_has_session_entry;
extern const struct cmd_entry cmd_if_shell_entry;
@ -94,7 +92,6 @@ extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_access_entry;
extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry;
extern const struct cmd_entry cmd_set_hook_entry;
@ -105,7 +102,6 @@ extern const struct cmd_entry cmd_show_environment_entry;
extern const struct cmd_entry cmd_show_hooks_entry;
extern const struct cmd_entry cmd_show_messages_entry;
extern const struct cmd_entry cmd_show_options_entry;
extern const struct cmd_entry cmd_show_prompt_history_entry;
extern const struct cmd_entry cmd_show_window_options_entry;
extern const struct cmd_entry cmd_source_file_entry;
extern const struct cmd_entry cmd_split_window_entry;
@ -116,6 +112,7 @@ extern const struct cmd_entry cmd_swap_window_entry;
extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_up_pane_entry;
extern const struct cmd_entry cmd_wait_for_entry;
const struct cmd_entry *cmd_table[] = {
@ -127,17 +124,14 @@ const struct cmd_entry *cmd_table[] = {
&cmd_choose_client_entry,
&cmd_choose_tree_entry,
&cmd_clear_history_entry,
&cmd_clear_prompt_history_entry,
&cmd_clock_mode_entry,
&cmd_command_prompt_entry,
&cmd_confirm_before_entry,
&cmd_copy_mode_entry,
&cmd_customize_mode_entry,
&cmd_delete_buffer_entry,
&cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry,
&cmd_display_popup_entry,
&cmd_display_panes_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,
@ -186,7 +180,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_select_window_entry,
&cmd_send_keys_entry,
&cmd_send_prefix_entry,
&cmd_server_access_entry,
&cmd_set_buffer_entry,
&cmd_set_environment_entry,
&cmd_set_hook_entry,
@ -197,7 +190,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_show_hooks_entry,
&cmd_show_messages_entry,
&cmd_show_options_entry,
&cmd_show_prompt_history_entry,
&cmd_show_window_options_entry,
&cmd_source_file_entry,
&cmd_split_window_entry,
@ -212,23 +204,8 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
/* Instance of a command. */
struct cmd {
const struct cmd_entry *entry;
struct args *args;
u_int group;
char *file;
u_int line;
TAILQ_ENTRY(cmd) qentry;
};
TAILQ_HEAD(cmds, cmd);
/* Next group number for new command list. */
static u_int cmd_list_next_group = 1;
/* Log an argument vector. */
void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{
@ -245,9 +222,8 @@ cmd_log_argv(int argc, char **argv, const char *fmt, ...)
free(prefix);
}
/* Prepend to an argument vector. */
void
cmd_prepend_argv(int *argc, char ***argv, const char *arg)
cmd_prepend_argv(int *argc, char ***argv, char *arg)
{
char **new_argv;
int i;
@ -262,15 +238,13 @@ cmd_prepend_argv(int *argc, char ***argv, const char *arg)
(*argc)++;
}
/* Append to an argument vector. */
void
cmd_append_argv(int *argc, char ***argv, const char *arg)
cmd_append_argv(int *argc, char ***argv, char *arg)
{
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
(*argv)[(*argc)++] = xstrdup(arg);
}
/* Pack an argument vector up into a buffer. */
int
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);
}
/* Unpack an argument vector from a packed buffer. */
int
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);
}
/* Copy an argument vector, ensuring it is terminated by NULL. */
char **
cmd_copy_argv(int argc, char **argv)
{
@ -339,7 +311,6 @@ cmd_copy_argv(int argc, char **argv)
return (new_argv);
}
/* Free an argument vector. */
void
cmd_free_argv(int argc, char **argv)
{
@ -352,67 +323,32 @@ cmd_free_argv(int argc, char **argv)
free(argv);
}
/* Convert argument vector to a string. */
char *
cmd_stringify_argv(int argc, char **argv)
{
char *buf = NULL, *s;
size_t len = 0;
char *buf;
int i;
size_t len;
if (argc == 0)
return (xstrdup(""));
for (i = 0; i < argc; i++) {
s = args_escape(argv[i]);
log_debug("%s: %u %s = %s", __func__, i, argv[i], s);
len = 0;
buf = NULL;
len += strlen(s) + 1;
for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1;
buf = xrealloc(buf, len);
if (i == 0)
*buf = '\0';
else
strlcat(buf, " ", len);
strlcat(buf, s, len);
free(s);
strlcat(buf, argv[i], len);
}
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 *
cmd_get_alias(const char *name)
{
@ -443,8 +379,7 @@ cmd_get_alias(const char *name)
return (NULL);
}
/* Look up a command entry by name. */
const struct cmd_entry *
static const struct cmd_entry *
cmd_find(const char *name, char **cause)
{
const struct cmd_entry **loop, *entry, *found = NULL;
@ -493,34 +428,32 @@ ambiguous:
return (NULL);
}
/* Parse a single command from an argument vector. */
struct cmd *
cmd_parse(struct args_value *values, u_int count, const char *file, u_int line,
char **cause)
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
const struct cmd_entry *entry;
const char *name;
struct cmd *cmd;
struct args *args;
char *error = NULL;
if (count == 0 || values[0].type != ARGS_STRING) {
if (argc == 0) {
xasprintf(cause, "no command");
return (NULL);
}
entry = cmd_find(values[0].string, cause);
name = argv[0];
entry = cmd_find(name, cause);
if (entry == NULL)
return (NULL);
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
args = args_parse(&entry->args, values, count, &error);
if (args == NULL && error == NULL) {
xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
return (NULL);
}
if (args == NULL) {
xasprintf(cause, "command %s: %s", entry->name, error);
free(error);
return (NULL);
}
args = args_parse(entry->args.template, argc, argv);
if (args == NULL)
goto usage;
if (entry->args.lower != -1 && args->argc < entry->args.lower)
goto usage;
if (entry->args.upper != -1 && args->argc > entry->args.upper)
goto usage;
cmd = xcalloc(1, sizeof *cmd);
cmd->entry = entry;
@ -530,37 +463,31 @@ cmd_parse(struct args_value *values, u_int count, const char *file, u_int line,
cmd->file = xstrdup(file);
cmd->line = line;
cmd->alias = NULL;
cmd->argc = argc;
cmd->argv = cmd_copy_argv(argc, argv);
return (cmd);
usage:
if (args != NULL)
args_free(args);
xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
return (NULL);
}
/* Free a command. */
void
cmd_free(struct cmd *cmd)
{
free(cmd->alias);
cmd_free_argv(cmd->argc, cmd->argv);
free(cmd->file);
args_free(cmd->args);
free(cmd);
}
/* Copy a command. */
struct cmd *
cmd_copy(struct cmd *cmd, int argc, char **argv)
{
struct cmd *new_cmd;
new_cmd = xcalloc(1, sizeof *new_cmd);
new_cmd->entry = cmd->entry;
new_cmd->args = args_copy(cmd->args, argc, argv);
if (cmd->file != NULL)
new_cmd->file = xstrdup(cmd->file);
new_cmd->line = cmd->line;
return (new_cmd);
}
/* Get a command as a string. */
char *
cmd_print(struct cmd *cmd)
{
@ -576,7 +503,6 @@ cmd_print(struct cmd *cmd)
return (out);
}
/* Create a new command list. */
struct cmd_list *
cmd_list_new(void)
{
@ -585,39 +511,29 @@ cmd_list_new(void)
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
cmdlist->list = xcalloc(1, sizeof *cmdlist->list);
TAILQ_INIT(cmdlist->list);
TAILQ_INIT(&cmdlist->list);
return (cmdlist);
}
/* Append a command to a command list. */
void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{
cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
/* Append all commands from one list to another. */
void
cmd_list_append_all(struct cmd_list *cmdlist, struct cmd_list *from)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, from->list, qentry)
cmd->group = cmdlist->group;
TAILQ_CONCAT(cmdlist->list, from->list, qentry);
}
/* Move all commands from one command list to another. */
void
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++;
}
/* Free a command list. */
void
cmd_list_free(struct cmd_list *cmdlist)
{
@ -626,77 +542,36 @@ cmd_list_free(struct cmd_list *cmdlist)
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(cmdlist->list, cmd, qentry);
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist->list);
free(cmdlist);
}
/* Copy a command list, expanding %s in arguments. */
struct cmd_list *
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
char *
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd;
struct cmd_list *new_cmdlist;
struct cmd *new_cmd;
u_int group = cmdlist->group;
char *s;
s = cmd_list_print(cmdlist, 0);
log_debug("%s: %s", __func__, s);
free(s);
new_cmdlist = cmd_list_new();
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (cmd->group != group) {
new_cmdlist->group = cmd_list_next_group++;
group = cmd->group;
}
new_cmd = cmd_copy(cmd, argc, argv);
cmd_list_append(new_cmdlist, new_cmd);
}
s = cmd_list_print(new_cmdlist, 0);
log_debug("%s: %s", __func__, s);
free(s);
return (new_cmdlist);
}
/* Get a command list as a string. */
char *
cmd_list_print(const struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd, *next;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 6;
len += strlen(this) + 4;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
next = TAILQ_NEXT(cmd, qentry);
if (next != NULL) {
if (cmd->group != next->group) {
if (escaped)
strlcat(buf, " \\;\\; ", len);
else
strlcat(buf, " ;; ", len);
} else {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
if (TAILQ_NEXT(cmd, qentry) != NULL) {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
free(this);
@ -705,46 +580,6 @@ cmd_list_print(const struct cmd_list *cmdlist, int escaped)
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. */
int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
@ -810,14 +645,10 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
if ((wl = cmd_mouse_window(m, sp)) == NULL)
return (NULL);
if (m->wp == -1)
wp = wl->window->active;
else {
if ((wp = window_pane_find_by_id(m->wp)) == NULL)
return (NULL);
if (!window_has_pane(wl->window, wp))
return (NULL);
}
if ((wp = window_pane_find_by_id(m->wp)) == NULL)
return (NULL);
if (!window_has_pane(wl->window, wp))
return (NULL);
if (wlp != NULL)
*wlp = wl;
@ -829,7 +660,7 @@ char *
cmd_template_replace(const char *template, const char *s, int idx)
{
char ch, *buf;
const char *ptr, *cp, quote[] = "\"\\$;~";
const char *ptr, *cp, quote[] = "\"\\$;";
int replaced, quoted;
size_t len;

828
colour.c
View File

@ -22,7 +22,6 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tmux.h"
@ -105,21 +104,6 @@ colour_split_rgb(int c, u_char *r, u_char *g, u_char *b)
*b = c & 0xff;
}
/* Force colour to RGB if not already. */
int
colour_force_rgb(int c)
{
if (c & COLOUR_FLAG_RGB)
return (c);
if (c & COLOUR_FLAG_256)
return (colour_256toRGB(c));
if (c >= 0 && c <= 7)
return (colour_256toRGB(c));
if (c >= 90 && c <= 97)
return (colour_256toRGB(8 + c - 90));
return (-1);
}
/* Convert colour to a string. */
const char *
colour_tostring(int c)
@ -127,9 +111,6 @@ colour_tostring(int c)
static char s[32];
u_char r, g, b;
if (c == -1)
return ("none");
if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
@ -182,46 +163,6 @@ colour_tostring(int c)
return ("invalid");
}
/* Convert background colour to theme. */
enum client_theme
colour_totheme(int c)
{
int r, g, b, brightness;
if (c == -1)
return (THEME_UNKNOWN);
if (c & COLOUR_FLAG_RGB) {
r = (c >> 16) & 0xff;
g = (c >> 8) & 0xff;
b = (c >> 0) & 0xff;
brightness = r + g + b;
if (brightness > 382)
return (THEME_LIGHT);
return (THEME_DARK);
}
if (c & COLOUR_FLAG_256)
return (colour_totheme(colour_256toRGB(c)));
switch (c) {
case 0:
case 90:
return (THEME_DARK);
case 7:
case 97:
return (THEME_LIGHT);
default:
if (c >= 0 && c <= 7)
return (colour_totheme(colour_256toRGB(c)));
if (c >= 90 && c <= 97)
return (colour_totheme(colour_256toRGB(8 + c - 90)));
break;
}
return (THEME_UNKNOWN);
}
/* Convert colour from string. */
int
colour_fromstring(const char *s)
@ -248,12 +189,6 @@ colour_fromstring(const char *s)
return (-1);
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)
return (8);
@ -292,7 +227,7 @@ colour_fromstring(const char *s)
return (96);
if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
return (97);
return (colour_byname(s));
return (-1);
}
/* Convert 256 colour to RGB colour. */
@ -394,764 +329,3 @@ colour_256to16(int c)
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;
const char *errstr;
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
if (name[4] == '\0')
return (0xbebebe|COLOUR_FLAG_RGB);
c = strtonum(name + 4, 0, 100, &errstr);
if (errstr != NULL)
return (-1);
c = round(2.55 * c);
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);
}
/* Parse colour from an X11 string. */
int
colour_parseX11(const char *p)
{
double c, m, y, k = 0;
u_int r, g, b;
size_t len = strlen(p);
int colour = -1;
char *copy;
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
colour = colour_join_rgb(r, g, b);
else if ((len == 18 &&
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
colour = colour_join_rgb(
(1 - c) * (1 - k) * 255,
(1 - m) * (1 - k) * 255,
(1 - y) * (1 - k) * 255);
} else {
while (len != 0 && *p == ' ') {
p++;
len--;
}
while (len != 0 && p[len - 1] == ' ')
len--;
copy = xstrndup(p, len);
colour = colour_byname(copy);
free(copy);
}
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
return (colour);
}
/* Initialize palette. */
void
colour_palette_init(struct colour_palette *p)
{
p->fg = 8;
p->bg = 8;
p->palette = NULL;
p->default_palette = NULL;
}
/* Clear palette. */
void
colour_palette_clear(struct colour_palette *p)
{
if (p != NULL) {
p->fg = 8;
p->bg = 8;
free(p->palette);
p->palette = NULL;
}
}
/* Free a palette. */
void
colour_palette_free(struct colour_palette *p)
{
if (p != NULL) {
free(p->palette);
p->palette = NULL;
free(p->default_palette);
p->default_palette = NULL;
}
}
/* Get a colour from a palette. */
int
colour_palette_get(struct colour_palette *p, int c)
{
if (p == NULL)
return (-1);
if (c >= 90 && c <= 97)
c = 8 + c - 90;
else if (c & COLOUR_FLAG_256)
c &= ~COLOUR_FLAG_256;
else if (c >= 8)
return (-1);
if (p->palette != NULL && p->palette[c] != -1)
return (p->palette[c]);
if (p->default_palette != NULL && p->default_palette[c] != -1)
return (p->default_palette[c]);
return (-1);
}
/* Set a colour in a palette. */
int
colour_palette_set(struct colour_palette *p, int n, int c)
{
u_int i;
if (p == NULL || n > 255)
return (0);
if (c == -1 && p->palette == NULL)
return (0);
if (c != -1 && p->palette == NULL) {
if (p->palette == NULL)
p->palette = xcalloc(256, sizeof *p->palette);
for (i = 0; i < 256; i++)
p->palette[i] = -1;
}
p->palette[n] = c;
return (1);
}
/* Build palette defaults from an option. */
void
colour_palette_from_option(struct colour_palette *p, struct options *oo)
{
struct options_entry *o;
struct options_array_item *a;
u_int i, n;
int c;
if (p == NULL)
return;
o = options_get(oo, "pane-colours");
if ((a = options_array_first(o)) == NULL) {
if (p->default_palette != NULL) {
free(p->default_palette);
p->default_palette = NULL;
}
return;
}
if (p->default_palette == NULL)
p->default_palette = xcalloc(256, sizeof *p->default_palette);
for (i = 0; i < 256; i++)
p->default_palette[i] = -1;
while (a != NULL) {
n = options_array_item_index(a);
if (n < 256) {
c = options_array_item_value(a)->number;
p->default_palette[n] = c;
}
a = options_array_next(a);
}
}

145
compat.h
View File

@ -21,49 +21,15 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <fnmatch.h>
#include <limits.h>
#include <stdio.h>
#include <termios.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>
#ifndef EVBUFFER_EOL_LF
/*
* This doesn't really work because evbuffer_readline is broken, but gets us to
* build with very old (older than 1.4.14) libevent.
*/
#define EVBUFFER_EOL_LF
#define evbuffer_readln(a, b, c) evbuffer_readline(a)
#endif
#endif
#ifdef HAVE_MALLOC_TRIM
#include <malloc.h>
#endif
#ifdef HAVE_UTF8PROC
#include <utf8proc.h>
#endif
#ifndef __GNUC__
#define __attribute__(a)
#endif
#ifdef BROKEN___DEAD
#undef __dead
#endif
#ifndef __unused
#define __unused __attribute__ ((__unused__))
#endif
@ -73,9 +39,6 @@
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef __weak
#define __weak __attribute__ ((__weak__))
#endif
#ifndef ECHOPRT
#define ECHOPRT 0
@ -98,46 +61,19 @@ void warn(const char *, ...);
void warnx(const char *, ...);
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif
#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif
#ifndef _PATH_DEVNULL
#ifndef HAVE_PATHS_H
#define _PATH_BSHELL "/bin/sh"
#define _PATH_TMP "/tmp/"
#define _PATH_DEVNULL "/dev/null"
#endif
#ifndef _PATH_TTY
#define _PATH_TTY "/dev/tty"
#endif
#ifndef _PATH_DEV
#define _PATH_DEV "/dev/"
#endif
#ifndef _PATH_DEFPATH
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifndef _PATH_VI
#define _PATH_VI "/usr/bin/vi"
#endif
#ifndef __OpenBSD__
#define pledge(s, p) (0)
#endif
#ifndef IMAXBEL
#define IMAXBEL 0
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
@ -162,6 +98,10 @@ void warnx(const char *, ...);
#include "compat/bitstring.h"
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
@ -214,14 +154,6 @@ void warnx(const char *, ...);
#define O_DIRECTORY 0
#endif
#ifndef FNM_CASEFOLD
#ifdef FNM_IGNORECASE
#define FNM_CASEFOLD FNM_IGNORECASE
#else
#define FNM_CASEFOLD 0
#endif
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
@ -273,13 +205,6 @@ void warnx(const char *, ...);
#define HOST_NAME_MAX 255
#endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef HAVE_FLOCK
#define LOCK_SH 0
#define LOCK_EX 0
@ -297,11 +222,6 @@ void explicit_bzero(void *, size_t);
int getdtablecount(void);
#endif
#ifndef HAVE_GETDTABLESIZE
/* getdtablesize.c */
int getdtablesize(void);
#endif
#ifndef HAVE_CLOSEFROM
/* closefrom.c */
void closefrom(int);
@ -347,23 +267,6 @@ char *strndup(const char *, size_t);
void *memmem(const void *, size_t, const void *, size_t);
#endif
#ifndef HAVE_HTONLL
/* htonll.c */
#undef htonll
uint64_t htonll(uint64_t);
#endif
#ifndef HAVE_NTOHLL
/* ntohll.c */
#undef ntohll
uint64_t ntohll(uint64_t);
#endif
#ifndef HAVE_GETPEEREID
/* getpeereid.c */
int getpeereid(int, uid_t *, gid_t *);
#endif
#ifndef HAVE_DAEMON
/* daemon.c */
int daemon(int, int);
@ -379,11 +282,6 @@ const char *getprogname(void);
void setproctitle(const char *, ...);
#endif
#ifndef HAVE_CLOCK_GETTIME
/* clock_gettime.c */
int clock_gettime(int, struct timespec *);
#endif
#ifndef HAVE_B64_NTOP
/* base64.c */
#undef b64_ntop
@ -415,11 +313,6 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *);
#endif
#ifndef HAVE_GETLINE
/* getline.c */
ssize_t getline(char **, size_t *, FILE *);
#endif
#ifndef HAVE_SETENV
/* setenv.c */
int setenv(const char *, const char *, int);
@ -446,13 +339,6 @@ void *reallocarray(void *, size_t, size_t);
void *recallocarray(void *, size_t, size_t, size_t);
#endif
#ifdef HAVE_SYSTEMD
/* systemd.c */
int systemd_activated(void);
int systemd_create_socket(int, char **);
int systemd_move_to_new_cgroup(char **);
#endif
#ifdef HAVE_UTF8PROC
/* utf8proc.c */
int utf8proc_wcwidth(wchar_t);
@ -460,17 +346,13 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifdef NEED_FUZZING
/* tmux.c */
#define main __weak main
#endif
#ifndef HAVE_GETOPT
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;
extern int BSDoptopt;
extern int BSDoptreset;
extern char *BSDoptarg;
extern int BSDopterr;
extern int BSDoptind;
extern int BSDoptopt;
extern int BSDoptreset;
extern char *BSDoptarg;
int BSDgetopt(int, char *const *, const char *);
#define getopt(ac, av, o) BSDgetopt(ac, av, o)
#define opterr BSDopterr
@ -478,5 +360,6 @@ int BSDgetopt(int, char *const *, const char *);
#define optopt BSDoptopt
#define optreset BSDoptreset
#define optarg BSDoptarg
#endif
#endif /* COMPAT_H */

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(__unused 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>
# endif
#endif
#if defined(HAVE_LIBPROC_H)
# include <libproc.h>
#endif
#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 $";
#endif /* lint */
#ifndef HAVE_FCNTL_CLOSEM
/*
* Close all file descriptors greater than or equal to lowfd.
*/
static void
closefrom_fallback(int lowfd)
#ifdef HAVE_FCNTL_CLOSEM
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
* resource limits since it is possible to open a file descriptor
@ -78,78 +99,11 @@ closefrom_fallback(int lowfd)
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
maxfd = OPEN_MAX;
maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; 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;
(void) close((int) fd);
}
/* /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_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);
}

115
compat/getopt.c Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
#include "compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int BSDopterr = 1, /* if error message should be printed */
BSDoptind = 1, /* index into parent argv vector */
BSDoptopt, /* character checked for validity */
BSDoptreset; /* reset getopt */
char *BSDoptarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
BSDgetopt(int nargc, char *const *nargv, const char *ostr)
{
static const char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (ostr == NULL)
return (-1);
if (BSDoptreset || !*place) { /* update scanning pointer */
BSDoptreset = 0;
if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
if (place[1])
return (BADCH);
++BSDoptind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((BSDoptopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, BSDoptopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (BSDoptopt == (int)'-')
return (-1);
if (!*place)
++BSDoptind;
if (BSDopterr && *ostr != ':')
(void)fprintf(stderr,
"%s: unknown option -- %c\n", getprogname(),
BSDoptopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
BSDoptarg = NULL;
if (!*place)
++BSDoptind;
}
else { /* need an argument */
if (*place) /* no white space */
BSDoptarg = (char *)place;
else if (nargc <= ++BSDoptind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (BSDopterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
getprogname(), BSDoptopt);
return (BADCH);
}
else /* white space */
BSDoptarg = nargv[BSDoptind];
place = EMSG;
++BSDoptind;
}
return (BSDoptopt); /* dump back option letter */
}

View File

@ -1,577 +0,0 @@
/* This file is obtained from OpenSSH:
* Repository: https://github.com/openssh/openssh-portable
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
* File: /openbsd-compat/getopt_long.c */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* 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.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
#include "compat.h"
/* The following macro constants are taken from getopt.h of OpenSSH:
* Repository: https://github.com/openssh/openssh-portable
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
* File: /openbsd-compat/getopt.h
*
* ---- BEGIN - Copyright notice and license of getopt.h ----
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* 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.
* ---- END ----
*/
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
#if 0
#include <err.h>
#include <getopt.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG (char *)""
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#if 0
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
#endif
#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */

View File

@ -1,57 +0,0 @@
/*
* Copyright (c) 2022 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/socket.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#include "compat.h"
int
getpeereid(int s, uid_t *uid, gid_t *gid)
{
#ifdef HAVE_SO_PEERCRED
struct ucred uc;
int len = sizeof uc;
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &len) == -1)
return (-1);
*uid = uc.uid;
*gid = uc.gid;
return (0);
#elif defined(HAVE_GETPEERUCRED)
ucred_t *ucred = NULL;
if (getpeerucred(s, &ucred) == -1)
return (-1);
if ((*uid = ucred_geteuid(ucred)) == -1)
return (-1);
if ((*gid = ucred_getrgid(ucred)) == -1)
return (-1);
ucred_free(ucred);
return (0);
#else
*uid = geteuid();
*gid = getegid();
return (0);
#endif
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2024 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 <arpa/inet.h>
#include <sys/types.h>
#include "compat.h"
uint64_t
htonll(uint64_t v)
{
uint32_t b;
uint32_t t;
b = htonl (v & 0xffffffff);
t = htonl (v >> 32);
return ((uint64_t)b << 32 | t);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
/* $OpenBSD: imsg.c,v 1.37 2024/11/26 13:57:31 claudio Exp $ */
/* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
/*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -22,7 +21,6 @@
#include <sys/uio.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -30,288 +28,203 @@
#include "compat.h"
#include "imsg.h"
#define IMSG_ALLOW_FDPASS 0x01
#define IMSG_FD_MARK 0x80000000U
int imsg_fd_overhead = 0;
static struct ibuf *imsg_parse_hdr(struct ibuf *, void *, int *);
int
imsgbuf_init(struct imsgbuf *imsgbuf, int fd)
{
imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr,
imsgbuf);
if (imsgbuf->w == NULL)
return (-1);
imsgbuf->pid = getpid();
imsgbuf->maxsize = MAX_IMSGSIZE;
imsgbuf->fd = fd;
imsgbuf->flags = 0;
return (0);
}
static int imsg_get_fd(struct imsgbuf *);
void
imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf)
imsg_init(struct imsgbuf *ibuf, int fd)
{
imsgbuf->flags |= IMSG_ALLOW_FDPASS;
}
int
imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize)
{
if (maxsize < IMSG_HEADER_SIZE || maxsize & IMSG_FD_MARK) {
errno = EINVAL;
return (-1);
}
imsgbuf->maxsize = maxsize;
return (0);
}
int
imsgbuf_read(struct imsgbuf *imsgbuf)
{
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
return msgbuf_read(imsgbuf->fd, imsgbuf->w);
else
return ibuf_read(imsgbuf->fd, imsgbuf->w);
}
int
imsgbuf_write(struct imsgbuf *imsgbuf)
{
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
return msgbuf_write(imsgbuf->fd, imsgbuf->w);
else
return ibuf_write(imsgbuf->fd, imsgbuf->w);
}
int
imsgbuf_flush(struct imsgbuf *imsgbuf)
{
while (imsgbuf_queuelen(imsgbuf) > 0) {
if (imsgbuf_write(imsgbuf) == -1)
return (-1);
}
return (0);
}
void
imsgbuf_clear(struct imsgbuf *imsgbuf)
{
msgbuf_free(imsgbuf->w);
imsgbuf->w = NULL;
}
uint32_t
imsgbuf_queuelen(struct imsgbuf *imsgbuf)
{
return msgbuf_queuelen(imsgbuf->w);
msgbuf_init(&ibuf->w);
memset(&ibuf->r, 0, sizeof(ibuf->r));
ibuf->fd = fd;
ibuf->w.fd = fd;
ibuf->pid = getpid();
TAILQ_INIT(&ibuf->fds);
}
ssize_t
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
imsg_read(struct imsgbuf *ibuf)
{
struct imsg m;
struct ibuf *buf;
struct msghdr msg;
struct cmsghdr *cmsg;
union {
struct cmsghdr hdr;
char buf[CMSG_SPACE(sizeof(int) * 1)];
} cmsgbuf;
struct iovec iov;
ssize_t n = -1;
int fd;
struct imsg_fd *ifd;
if ((buf = msgbuf_get(imsgbuf->w)) == NULL)
memset(&msg, 0, sizeof(msg));
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
return (-1);
again:
if (getdtablecount() + imsg_fd_overhead +
(int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
>= getdtablesize()) {
errno = EAGAIN;
free(ifd);
return (-1);
}
if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
if (errno == EINTR)
goto again;
goto fail;
}
ibuf->r.wpos += n;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
int i;
int j;
/*
* We only accept one file descriptor. Due to C
* padding rules, our control buffer might contain
* more than one fd, and we must close them.
*/
j = ((char *)cmsg + cmsg->cmsg_len -
(char *)CMSG_DATA(cmsg)) / sizeof(int);
for (i = 0; i < j; i++) {
fd = ((int *)CMSG_DATA(cmsg))[i];
if (ifd != NULL) {
ifd->fd = fd;
TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
entry);
ifd = NULL;
} else
close(fd);
}
}
/* we do not handle other ctl data level */
}
fail:
free(ifd);
return (n);
}
ssize_t
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
{
size_t av, left, datalen;
av = ibuf->r.wpos;
if (IMSG_HEADER_SIZE > av)
return (0);
if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
if (imsg->hdr.len < IMSG_HEADER_SIZE ||
imsg->hdr.len > MAX_IMSGSIZE) {
errno = ERANGE;
return (-1);
}
if (imsg->hdr.len > av)
return (0);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
if (datalen == 0)
imsg->data = NULL;
else if ((imsg->data = malloc(datalen)) == NULL)
return (-1);
if (ibuf_size(buf))
m.data = ibuf_data(buf);
if (imsg->hdr.flags & IMSGF_HASFD)
imsg->fd = imsg_get_fd(ibuf);
else
m.data = NULL;
m.buf = buf;
m.hdr.len &= ~IMSG_FD_MARK;
imsg->fd = -1;
*imsg = m;
return (ibuf_size(buf) + IMSG_HEADER_SIZE);
memcpy(imsg->data, ibuf->r.rptr, datalen);
if (imsg->hdr.len < av) {
left = av - imsg->hdr.len;
memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
ibuf->r.wpos = left;
} else
ibuf->r.wpos = 0;
return (datalen + IMSG_HEADER_SIZE);
}
int
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
{
if (ibuf_size(imsg->buf) == 0) {
errno = EBADMSG;
return (-1);
}
return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf);
}
int
imsg_get_data(struct imsg *imsg, void *data, size_t len)
{
if (len == 0) {
errno = EINVAL;
return (-1);
}
if (ibuf_size(imsg->buf) != len) {
errno = EBADMSG;
return (-1);
}
return ibuf_get(imsg->buf, data, len);
}
int
imsg_get_fd(struct imsg *imsg)
{
return ibuf_fd_get(imsg->buf);
}
uint32_t
imsg_get_id(struct imsg *imsg)
{
return (imsg->hdr.peerid);
}
size_t
imsg_get_len(struct imsg *imsg)
{
return ibuf_size(imsg->buf);
}
pid_t
imsg_get_pid(struct imsg *imsg)
{
return (imsg->hdr.pid);
}
uint32_t
imsg_get_type(struct imsg *imsg)
{
return (imsg->hdr.type);
}
int
imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
int fd, const void *data, size_t datalen)
imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
int fd, const void *data, uint16_t datalen)
{
struct ibuf *wbuf;
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1);
if (imsg_add(wbuf, data, datalen) == -1)
return (-1);
ibuf_fd_set(wbuf, fd);
imsg_close(imsgbuf, wbuf);
wbuf->fd = fd;
imsg_close(ibuf, wbuf);
return (1);
}
int
imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
int fd, const struct iovec *iov, int iovcnt)
{
struct ibuf *wbuf;
int i;
size_t datalen = 0;
int i, datalen = 0;
for (i = 0; i < iovcnt; i++)
datalen += iov[i].iov_len;
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1);
for (i = 0; i < iovcnt; i++)
if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
return (-1);
ibuf_fd_set(wbuf, fd);
imsg_close(imsgbuf, wbuf);
wbuf->fd = fd;
imsg_close(ibuf, wbuf);
return (1);
}
/*
* Enqueue imsg with payload from ibuf buf. fd passing is not possible
* with this function.
*/
int
imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
pid_t pid, struct ibuf *buf)
{
struct ibuf *hdrbuf = NULL;
struct imsg_hdr hdr;
int save_errno;
if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) {
errno = ERANGE;
goto fail;
}
hdr.type = type;
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
hdr.peerid = id;
if ((hdr.pid = pid) == 0)
hdr.pid = imsgbuf->pid;
if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
goto fail;
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
goto fail;
ibuf_close(imsgbuf->w, hdrbuf);
ibuf_close(imsgbuf->w, buf);
return (1);
fail:
save_errno = errno;
ibuf_free(buf);
ibuf_free(hdrbuf);
errno = save_errno;
return (-1);
}
/*
* Forward imsg to another channel. Any attached fd is closed.
*/
int
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
{
struct ibuf *wbuf;
size_t len;
ibuf_rewind(msg->buf);
ibuf_skip(msg->buf, sizeof(msg->hdr));
len = ibuf_size(msg->buf);
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
msg->hdr.pid, len)) == NULL)
return (-1);
if (len != 0) {
if (ibuf_add_ibuf(wbuf, msg->buf) == -1) {
ibuf_free(wbuf);
return (-1);
}
}
imsg_close(imsgbuf, wbuf);
return (1);
}
/* ARGSUSED */
struct ibuf *
imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
size_t datalen)
imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
uint16_t datalen)
{
struct ibuf *wbuf;
struct imsg_hdr hdr;
datalen += IMSG_HEADER_SIZE;
if (datalen > imsgbuf->maxsize) {
if (datalen > MAX_IMSGSIZE) {
errno = ERANGE;
return (NULL);
}
hdr.type = type;
hdr.peerid = id;
hdr.flags = 0;
hdr.peerid = peerid;
if ((hdr.pid = pid) == 0)
hdr.pid = imsgbuf->pid;
if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) {
hdr.pid = ibuf->pid;
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
return (NULL);
}
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
@ -321,7 +234,7 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
}
int
imsg_add(struct ibuf *msg, const void *data, size_t datalen)
imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
{
if (datalen)
if (ibuf_add(msg, data, datalen) == -1) {
@ -332,47 +245,58 @@ imsg_add(struct ibuf *msg, const void *data, size_t datalen)
}
void
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
{
struct imsg_hdr *hdr;
uint32_t len;
len = ibuf_size(msg);
if (ibuf_fd_avail(msg))
len |= IMSG_FD_MARK;
(void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len);
ibuf_close(imsgbuf->w, msg);
hdr = (struct imsg_hdr *)msg->buf;
hdr->flags &= ~IMSGF_HASFD;
if (msg->fd != -1)
hdr->flags |= IMSGF_HASFD;
hdr->len = (uint16_t)msg->wpos;
ibuf_close(&ibuf->w, msg);
}
void
imsg_free(struct imsg *imsg)
{
ibuf_free(imsg->buf);
freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
}
static struct ibuf *
imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd)
static int
imsg_get_fd(struct imsgbuf *ibuf)
{
struct imsgbuf *imsgbuf = arg;
struct imsg_hdr hdr;
struct ibuf *b;
uint32_t len;
int fd;
struct imsg_fd *ifd;
if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1)
return (NULL);
if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
return (-1);
len = hdr.len & ~IMSG_FD_MARK;
fd = ifd->fd;
TAILQ_REMOVE(&ibuf->fds, ifd, entry);
free(ifd);
if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) {
errno = ERANGE;
return (NULL);
}
if ((b = ibuf_open(len)) == NULL)
return (NULL);
if (hdr.len & IMSG_FD_MARK) {
ibuf_fd_set(b, *fd);
*fd = -1;
}
return b;
return (fd);
}
int
imsg_flush(struct imsgbuf *ibuf)
{
while (ibuf->w.queued)
if (msgbuf_write(&ibuf->w) <= 0)
return (-1);
return (0);
}
void
imsg_clear(struct imsgbuf *ibuf)
{
int fd;
msgbuf_clear(&ibuf->w);
while ((fd = imsg_get_fd(ibuf)) != -1)
close(fd);
}

View File

@ -1,7 +1,6 @@
/* $OpenBSD: imsg.h,v 1.19 2024/11/26 13:57:31 claudio Exp $ */
/* $OpenBSD: imsg.h,v 1.4 2017/03/24 09:34:12 nicm Exp $ */
/*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
* Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -22,15 +21,13 @@
#ifndef _IMSG_H_
#define _IMSG_H_
#include <sys/types.h>
#define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384
struct ibuf {
TAILQ_ENTRY(ibuf) entry;
unsigned char *buf;
u_char *buf;
size_t size;
size_t max;
size_t wpos;
@ -38,116 +35,77 @@ struct ibuf {
int fd;
};
struct msgbuf;
struct msgbuf {
TAILQ_HEAD(, ibuf) bufs;
uint32_t queued;
int fd;
};
struct ibuf_read {
u_char buf[IBUF_READ_SIZE];
u_char *rptr;
size_t wpos;
};
struct imsg_fd {
TAILQ_ENTRY(imsg_fd) entry;
int fd;
};
struct imsgbuf {
struct msgbuf *w;
pid_t pid;
uint32_t maxsize;
TAILQ_HEAD(, imsg_fd) fds;
struct ibuf_read r;
struct msgbuf w;
int fd;
int flags;
pid_t pid;
};
#define IMSGF_HASFD 1
struct imsg_hdr {
uint32_t type;
uint32_t len;
uint16_t len;
uint16_t flags;
uint32_t peerid;
uint32_t pid;
};
struct imsg {
struct imsg_hdr hdr;
int fd;
void *data;
struct ibuf *buf;
};
struct iovec;
/* imsg-buffer.c */
/* buffer.c */
struct ibuf *ibuf_open(size_t);
struct ibuf *ibuf_dynamic(size_t, size_t);
int ibuf_add(struct ibuf *, const void *, size_t);
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_add_zero(struct ibuf *, size_t);
int ibuf_add_n8(struct ibuf *, uint64_t);
int ibuf_add_n16(struct ibuf *, uint64_t);
int ibuf_add_n32(struct ibuf *, uint64_t);
int ibuf_add_n64(struct ibuf *, uint64_t);
int ibuf_add_h16(struct ibuf *, uint64_t);
int ibuf_add_h32(struct ibuf *, uint64_t);
int ibuf_add_h64(struct ibuf *, uint64_t);
void *ibuf_reserve(struct ibuf *, size_t);
void *ibuf_seek(struct ibuf *, size_t, size_t);
int ibuf_set(struct ibuf *, size_t, const void *, size_t);
int ibuf_set_n8(struct ibuf *, size_t, uint64_t);
int ibuf_set_n16(struct ibuf *, size_t, uint64_t);
int ibuf_set_n32(struct ibuf *, size_t, uint64_t);
int ibuf_set_n64(struct ibuf *, size_t, uint64_t);
int ibuf_set_h16(struct ibuf *, size_t, uint64_t);
int ibuf_set_h32(struct ibuf *, size_t, uint64_t);
int ibuf_set_h64(struct ibuf *, size_t, uint64_t);
void *ibuf_data(const struct ibuf *);
size_t ibuf_size(const struct ibuf *);
size_t ibuf_left(const struct ibuf *);
int ibuf_truncate(struct ibuf *, size_t);
void ibuf_rewind(struct ibuf *);
size_t ibuf_size(struct ibuf *);
size_t ibuf_left(struct ibuf *);
void ibuf_close(struct msgbuf *, struct ibuf *);
void ibuf_from_buffer(struct ibuf *, void *, size_t);
void ibuf_from_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_get(struct ibuf *, void *, size_t);
int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *);
int ibuf_get_n8(struct ibuf *, uint8_t *);
int ibuf_get_n16(struct ibuf *, uint16_t *);
int ibuf_get_n32(struct ibuf *, uint32_t *);
int ibuf_get_n64(struct ibuf *, uint64_t *);
int ibuf_get_h16(struct ibuf *, uint16_t *);
int ibuf_get_h32(struct ibuf *, uint32_t *);
int ibuf_get_h64(struct ibuf *, uint64_t *);
char *ibuf_get_string(struct ibuf *, size_t);
int ibuf_skip(struct ibuf *, size_t);
int ibuf_write(struct msgbuf *);
void ibuf_free(struct ibuf *);
int ibuf_fd_avail(struct ibuf *);
int ibuf_fd_get(struct ibuf *);
void ibuf_fd_set(struct ibuf *, int);
struct msgbuf *msgbuf_new(void);
struct msgbuf *msgbuf_new_reader(size_t,
struct ibuf *(*)(struct ibuf *, void *, int *), void *);
void msgbuf_free(struct msgbuf *);
void msgbuf_init(struct msgbuf *);
void msgbuf_clear(struct msgbuf *);
uint32_t msgbuf_queuelen(struct msgbuf *);
int ibuf_write(int, struct msgbuf *);
int msgbuf_write(int, struct msgbuf *);
int ibuf_read(int, struct msgbuf *);
int msgbuf_read(int, struct msgbuf *);
struct ibuf *msgbuf_get(struct msgbuf *);
int msgbuf_write(struct msgbuf *);
void msgbuf_drain(struct msgbuf *, size_t);
/* imsg.c */
int imsgbuf_init(struct imsgbuf *, int);
void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf);
int imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
int imsgbuf_read(struct imsgbuf *);
int imsgbuf_write(struct imsgbuf *);
int imsgbuf_flush(struct imsgbuf *);
void imsgbuf_clear(struct imsgbuf *);
uint32_t imsgbuf_queuelen(struct imsgbuf *);
void imsg_init(struct imsgbuf *, int);
ssize_t imsg_read(struct imsgbuf *);
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
int imsg_get_ibuf(struct imsg *, struct ibuf *);
int imsg_get_data(struct imsg *, void *, size_t);
int imsg_get_fd(struct imsg *);
uint32_t imsg_get_id(struct imsg *);
size_t imsg_get_len(struct imsg *);
pid_t imsg_get_pid(struct imsg *);
uint32_t imsg_get_type(struct imsg *);
int imsg_forward(struct imsgbuf *, struct imsg *);
int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const void *, size_t);
const void *, uint16_t);
int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const struct iovec *, int);
int imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t,
struct ibuf *);
struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t);
int imsg_add(struct ibuf *, const void *, size_t);
struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, uint16_t);
int imsg_add(struct ibuf *, const void *, uint16_t);
void imsg_close(struct imsgbuf *, struct ibuf *);
void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);
void imsg_clear(struct imsgbuf *);
#endif

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