1 Commits
1.4 ... 1.3

Author SHA1 Message Date
no_author
946fd162ba This commit was manufactured by cvs2svn to create tag 'TMUX_1_3'. 2010-07-18 13:41:00 +00:00
71 changed files with 1194 additions and 2332 deletions

43
CHANGES
View File

@@ -1,44 +1,3 @@
CHANGES FROM 1.3 TO 1.4, 27 December 2010
* Window bell reporting fixed.
* Show which pane is active in the list-panes output.
* Backoff reworked.
* Prevent the server from dying when switching into copy mode when already
in a different mode.
* Reset running jobs when the status line is enabled or disabled.
* Simplify xterm modifier detection.
* Avoid crashing in copy mode if the screen size is too small for the
indicator.
* Flags -n and -p added to switch-client.
* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
terminals (eg putty) which disable the vt100 ACS mode switching sequences
in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
* New server option exit-unattached added.
* New session option destroy-unattached added.
* Fall back on normal session choice method if $TMUX exists but is invalid
rather than rejecting.
* Mark repeating keys with "(repeat)" in the key list.
* When removing a pane, don't change the active pane unless the active pane
is actually the one being removed.
* New command last-pane added.
* AIX fixes.
* Flag -a added to unbind-key.
* Add XAUTHORITY to update-environment.
* More info regarding window and pane flags is now shown in list-*.
* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
* New window option monitor-silence and session option visual-silence added.
* In the built-in layouts distribute the panes more evenly.
* Set the default value of main-pane-width to 80 instead of 81.
* Command-line flag -V added.
* Instead of keeping a per-client prompt history make it global.
* Fix rectangle copy to behave like emacs (the cursor is not part of the
selection on the right edge but on the left it is).
* Flag -l added to switch-client.
* Retrieve environment variables from the global environment rather than
getenv(3), thus allowing them to be updated during the configuration file.
* New window options other-pane-{height,width} added.
* More minor bugs fixed and manpage improvements.
CHANGES FROM 1.2 TO 1.3, 18 July 2010 CHANGES FROM 1.2 TO 1.3, 18 July 2010
* New input parser. * New input parser.
@@ -1554,7 +1513,7 @@ The list of older changes is below.
(including mutt, emacs). No status bar yet and no key remapping or other (including mutt, emacs). No status bar yet and no key remapping or other
customisation. customisation.
$Id: CHANGES,v 1.304 2010-12-27 21:37:42 tcunha Exp $ $Id: CHANGES,v 1.303 2010-07-18 13:40:59 tcunha Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

173
FAQ
View File

@@ -12,99 +12,29 @@ tmux frequently asked questions
* and derivatives. * * and derivatives. *
****************************************************************************** ******************************************************************************
* How is tmux different from GNU screen? * How is tmux different from GNU screen? What else does it offer?
tmux and GNU screen have many similarities. Some of the main differences I am tmux offers several advantages over screen:
aware of are (bearing in mind I haven't used screen for a few years now):
- tmux uses a client-server model. Each server has single Unix domain socket in - a clearly-defined client-server model: windows are independent entities which
/tmp and within one server there are multiple sessions which may be attached may be attached simultaneously to multiple sessions and viewed from multiple
to multiple clients (terminals). clients (terminals), as well as moved freely between sessions within the same
tmux server;
- a consistent, well-documented command interface, with the same syntax
whether used interactively, as a key binding, or from the shell;
- easily scriptable from the shell;
- multiple paste buffers;
- choice of vi or emacs key layouts;
- an option to limit the window size;
- a more usable status line syntax, with the ability to display the first line
of output of a specific command;
- a cleaner, modern, easily extended, BSD-licensed codebase.
This has advantages, notably: windows may be linked simultaneously to There are still a few features screen includes that tmux omits:
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
This model is different from screen, where typically each new screen instance - builtin serial and telnet support; this is bloat and is unlikely to be added
is independent. tmux supports the same behaviour by using multiple servers to tmux;
with the -L option but it is not typically recommended. - wider platform support, for example IRIX and HP-UX, and for odd terminals.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- screen has support for updating utmp. Nobody has really come up with a clean,
portable way to do this without making tmux setuid or setgid yet.
- Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX and HP-UX, and for odd
terminals.
* I found a bug! What do I do? * I found a bug! What do I do?
@@ -237,8 +167,6 @@ the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so it may be possible to configure vim to accept these, an example of how to do so
would be welcome. would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* Why doesn't elinks set the window title inside tmux? * Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so There isn't a way to detect if a terminal supports setting the window title, so
@@ -311,65 +239,4 @@ set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx
Note that this will only work in tmux 1.2 and above. Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window? $Id: FAQ,v 1.36 2010-02-04 21:01:59 nicm Exp $
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* How can I open a new window in the same directory as the current window?
One option is to just run "TMUX= tmux" in the window. However, this only works if no
command is running, so that you can input the command.
A workaround is to let tmux know about the current path through an environment
variable. To do so, use the following command:
[ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
Which sets TMUXPWD_i (where i is the number of the current window) to the path
of the current directory. This command can be added to PS1, for example:
PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
When a new window is created, the shell should be asked to change
directory. You can define a new binding (for example, if using GNU bash):
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
This solution will work even if a command is currently running in the terminal,
but it will not work from a window that has just been swapped with another
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
is displayed, TMUXPWD_i is updated properly.
* tmux doesn't start with "daemon failed"
tmux shows something similar to this when started:
fatal: server_start: daemon failed: No such file or directory
fatal: main_dispatch: imsg_read failed
A possible reason is that /dev/null is not a character device or is otherwise
inaccessible.
Check with:
file /dev/null
ls -l /dev/null
If it is not a character device or has incorrect permissions, it can typically
be recreated with:
cd /dev && rm null && ./MAKEDEV null
$Id: FAQ,v 1.41 2010-12-15 23:31:30 nicm Exp $

View File

@@ -1,4 +1,4 @@
# $Id: GNUmakefile,v 1.130 2010-12-27 21:32:16 tcunha Exp $ # $Id: GNUmakefile,v 1.128 2010-07-18 13:36:52 tcunha Exp $
# #
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> # Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
# #
@@ -17,7 +17,7 @@
.PHONY: clean .PHONY: clean
VERSION= 1.4 VERSION= 1.3
#FDEBUG= 1 #FDEBUG= 1

View File

@@ -1,4 +1,4 @@
# $Id: Makefile,v 1.162 2010-12-27 21:32:16 tcunha Exp $ # $Id: Makefile,v 1.160 2010-07-18 13:36:52 tcunha Exp $
# #
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> # Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
# #
@@ -18,7 +18,7 @@
.SUFFIXES: .c .o .SUFFIXES: .c .o
.PHONY: clean .PHONY: clean
VERSION= 1.4 VERSION= 1.3
#FDEBUG= 1 #FDEBUG= 1

25
NOTES
View File

@@ -25,11 +25,34 @@ windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information. the tmux(1) man page for further information.
The following is a summary of major features implemented in this version:
- Basic multiplexing, window switching, attaching and detaching.
- Window listing and renaming.
- Key binding.
- Handling of client terminal resize.
- Terminal emulation sufficient to handle most curses applications.
- A optional status line (enabled by default).
- Window history and copy and paste.
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity by running an external command.
- A configuration file.
- UTF-8 support.
A more extensive, but rough, todo list is included in the TODO file. A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly. are missing it may refuse to run, or not behave correctly.
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
this may be turned on for all windows by setting it as a global option, see
tmux(1) and the FAQ file. As of 0.9, tmux attempts to autodetect a
UTF-8 capable terminal by checking the LC_ALL, LC_CTYPE and LANG environment
variables. list-clients may be used to check if this is detected correctly; if
not, the -u command-line flag may be specified.
A Vim syntax file is available in the examples directory. To install it: A Vim syntax file is available in the examples directory. To install it:
- Drop the file in the syntax directory in your runtimepath (such as - Drop the file in the syntax directory in your runtimepath (such as
@@ -63,4 +86,4 @@ start. Please contact me with any queries.
-- Nicholas Marriott <nicm@users.sf.net> -- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.54 2010-12-27 21:36:37 tcunha Exp $ $Id: NOTES,v 1.53 2010-03-10 15:18:11 tcunha Exp $

88
TODO
View File

@@ -1,3 +1,4 @@
- window creation/idle time
- better errors when creating new windows/sessions (how?) - better errors when creating new windows/sessions (how?)
- implicitly add exec to the commands for new windows (switch to disable it)? - implicitly add exec to the commands for new windows (switch to disable it)?
- it would be nice to have multichar commands eg C-b K K - it would be nice to have multichar commands eg C-b K K
@@ -6,18 +7,26 @@
bring back detach-session to detach all clients on a session? bring back detach-session to detach all clients on a session?
- allow fnmatch for -c, so that you can, eg, detach all clients - allow fnmatch for -c, so that you can, eg, detach all clients
- garbage collect window history (100 lines at a time?) if it hasn't been used - garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time in $x time (need window creation/use times)
- lift SHRT_MAX limits for history? - lift SHRT_MAX limits for history?
- flags to centre screen in window - flags to centre screen in window
- better terminal emulation
- activity/bell should be per-window not per-link? what if it is cur win in - activity/bell should be per-window not per-link? what if it is cur win in
session not being watched? session not being watched?
- next prev word etc in command prompt - next prev word etc in command prompt
- many more info() displays for various things
- use a better termcap internally instead of screen, perhaps xterm - use a better termcap internally instead of screen, perhaps xterm
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- should be able to move to a hidden pane and it would be moved into view. pane - should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode - support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically? - set-remain-on-exit is a bit of a hack, some way to do it generically?
- set-option should be set-session-option and should be overall global options
also quiet, utf8 and maybe other flags?
-g is a bit unexpected in conf file
- clear window title on exit - clear window title on exit
- the output code (tty.c) could do with optimisation depending on term
capabilities
- would be nice to be able to use "--" to mark start of command w/ neww etc - would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting to avoid quoting
- make command sequences more usable: don't require space after ;, handle - make command sequences more usable: don't require space after ;, handle
@@ -28,7 +37,11 @@
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file "new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
$HOME/.tmux-session.conf $HOME/.tmux-session.conf
- get it passing all the vttest tests that don't require resizing the terminal - get it passing all the vttest tests that don't require resizing the terminal
- esc seq to set window name and title should be documented, and name variant
should clear automatic-rename
- way to set socket path from config file - way to set socket path from config file
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
when session is started
- what about utmp etc? can tmux update it like screen? setgid? - what about utmp etc? can tmux update it like screen? setgid?
- warts on current naming: - warts on current naming:
- display-time but message-fg/bg/attr - display-time but message-fg/bg/attr
@@ -36,30 +49,46 @@
- server-info - server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-* - up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- split-window -> split-pane?? - split-window -> split-pane??
- tidy up and prioritise todo list ;-)
- neww and attach can create a session if none exists?
would work fine with config file since
- a way for force-width/height to apply to only one pane (how?) - a way for force-width/height to apply to only one pane (how?)
- command to list what is actually running in each window with command line, - command to list what is actually running in each window with command line,
pid (need some adaption of the osdep code) pid (need some adaption of the osdep code)
- support for bce - support for bce
- it would be nice if the start/end line keys in copy mode were aware of
wrapped lines
- some way to force a screen to use the entire terminal even if it is forced - some way to force a screen to use the entire terminal even if it is forced
to be smaller by other clients. pan smaller terminal? (like screen F) to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets for redraw -- idea of a "view" onto a window, need base x/y offsets
for redraw
- handle resize better in copy mode - handle resize better in copy mode
- way to copy stuff that is off screen due to resize - way to copy stuff that is off screen due to resize
- commands should be able to succeed or fail and have || or && for command - commands should be able to succeed or fail and have || or && for command
lists lists
- support the mouse wheel to scroll through history
- some way to KEEP a command running continually and just use its LAST line of - some way to KEEP a command running continually and just use its LAST line of
output output
- bind commands to mouse buttons - bind commands to mouse buttons
- UTF-8 to a non-UTF-8 terminal should not be able to balls up - UTF-8 to a non-UTF-8 terminal should not be able to balls up
the terminal - www/ruby-addressable; make regress the terminal - www/ruby-addressable; make regress
- copy mode needs a tidy/cleanup
- ability to save history (to buffer?)
- multiple keys could be done with tables, ie have prefixes go and instead - multiple keys could be done with tables, ie have prefixes go and instead
bind -n ^A prefix-table "default" bind -n ^A prefix-table "default"
where prefix-table sets command lookup table and sets prefix flag, then next where prefix-table sets command lookup table and sets prefix flag, then next
key is looked up in that table key is looked up in that table
- UTF-8 should be a pointer into a combined string buffer
- check irssi (term_charset) works with UTF-8
- support esc-esc to quit in modes - support esc-esc to quit in modes
- fix ctrl+F1-F4 output. to what? - fix ctrl+F1-F4 output. to what?
- look into xterm clearing its selection when scrolling etc - look into xterm clearing its selection when scrolling etc
- better utf8 support: window names, prompt input, message display - better utf8 support:
window names
prompt input
message display
copy and paste cursor and wide characters
...?
- session history for client and last-session command - session history for client and last-session command
- option to change status line colour when current window is in a mode? - option to change status line colour when current window is in a mode?
- option to move copy mode indicator into status line - option to move copy mode indicator into status line
@@ -67,6 +96,7 @@
- selection behaviour closer to vi in vi mode - selection behaviour closer to vi in vi mode
- live update: server started with -U connects to server, requests sessions and - live update: server started with -U connects to server, requests sessions and
windows, receives fds windows, receives fds
- convert status line history to be server global (anything else?)
- command to show a tree of sessions-windows-panes (active marked with *) - command to show a tree of sessions-windows-panes (active marked with *)
- sort out inheriting config from shell on new sessions/windows: - sort out inheriting config from shell on new sessions/windows:
should pick up default-path/termios/etc from client if possible, should pick up default-path/termios/etc from client if possible,
@@ -80,7 +110,7 @@
- better session sharing: create-socket command to create socket somewhere (-r - better session sharing: create-socket command to create socket somewhere (-r
flag for readonly) flag for readonly)
- allow buffer to be specified when copying in copy mode - allow buffer to be specified when copying in copy mode
- multiline status line (no?) - multiline status line
- flag for absolute pane size to resize-pane - flag for absolute pane size to resize-pane
- sanity check input to socket - sanity check input to socket
- select-buffer command - select-buffer command
@@ -98,33 +128,25 @@
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command - ' and " should be parsed the same (eg "\e" vs '\e') in config and command
prompt? prompt?
- command to toggle selection not to move it in copy-mode - command to toggle selection not to move it in copy-mode
- why are alerts per-winlink? try per window?
- audit of escape sequence support vs xterm For 1.3 (not in order):
- support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
mouse click == select-pane -t %%, mouse scroll up == copy-mode) 3 why are alerts per-winlink? try per window?
- something for -t "last window in session" so a session can be used as a stack 4 audit of escape sequence support vs xterm
- synchronous commands - client sends cmd and blocks, neww/splitw saves client 6 rectangle copy: when selecting leftward, cursor should be inside block per
ptr then when program inside died, sends MSG_SOMETHING with wait status to emacs key to rotate corner at which cursor is
client 9 something for -t "last window in session" so a session can be used as a stack
- documentation improvements - rlpowell's tutorial - build instructions 10 synchronous commands - client sends cmd and blocks, neww/splitw saves client
- better configure? with-libevent ptr then when program inside died, sends MSG_SOMETHING with wait status to
- bind commands to key sequences? client
- monitor, bell etc should monitor /all/ panes in the window not just one 11 documentation improvements - rlpowell's tutorial
- a history of commands that can be reversed (reverse member of each command, - build instructions
and a buffer) info() when changing to same window 12 better configure? with-libevent
- don't pass UTF-8 through vis for titles 14 bind commands to key sequences?
- clearing screen should push lines into history 16 monitor, bell etc should monitor /all/ panes in the window not just one
- add a unique ever-increasing pane id to each pane, export it in $TMUX_PANE 17 wd should be updated on attach etc. maybe lose default-path and use PWD
(as %1, %2 etc) and allow it to be used as a target 18 a history of commands that can be reversed (reverse member of each command, and a buffer)
- way to add dest for break-pane; maybe some easier way to unbreak-pane 19 info() when changing to same window
- case insensitive searching 20 don't pass UTF-8 through vis for titles
- dynamically generated jobs (eg "date ...") do not work well because ...
their entries are never collected, should either store status jobs in
a different tree or flush all unused persist jobs every update rather
than just updating them
- pane-index option like base-index
- option to move status line to top
- support "xterm2" mouse mode
- respawn-pane command
- configurable borders and empty space filler for when panes < window?

347
client.c
View File

@@ -1,4 +1,4 @@
/* $Id: client.c,v 1.100 2010-10-24 19:54:41 nicm Exp $ */ /* $Id: client.c,v 1.95 2010-07-02 02:52:13 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,6 +28,7 @@
#include <pwd.h> #include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <syslog.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -36,173 +37,82 @@ struct imsgbuf client_ibuf;
struct event client_event; struct event client_event;
const char *client_exitmsg; const char *client_exitmsg;
int client_exitval; int client_exitval;
int client_attached;
int client_connect(char *, int);
void client_send_identify(int); void client_send_identify(int);
void client_send_environ(void); void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t); void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void); void client_update_event(void);
void client_signal(int, short, void *); void client_signal(int, short, void *);
void client_callback(int, short, void *); void client_callback(int, short, void *);
int client_dispatch_attached(void); int client_dispatch(void);
int client_dispatch_wait(void *);
/* Connect client to server. */ struct imsgbuf *
int client_init(char *path, int cmdflags, int flags)
client_connect(char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
int fd, mode; int fd, mode;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
#ifdef HAVE_SETPROCTITLE
if (realpath(path, rpathbuf) == NULL)
strlcpy(rpathbuf, path, sizeof rpathbuf);
setproctitle("client (%s)", rpathbuf);
#endif
memset(&sa, 0, sizeof sa); memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) { if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (-1); goto not_found;
} }
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed"); fatal("socket failed");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
if (!start_server) if (!(cmdflags & CMD_STARTSERVER))
goto failed; goto not_found;
switch (errno) { switch (errno) {
case ECONNREFUSED: case ECONNREFUSED:
if (unlink(path) != 0) if (unlink(path) != 0)
goto failed; goto not_found;
/* FALLTHROUGH */ /* FALLTHROUGH */
case ENOENT: case ENOENT:
if ((fd = server_start()) == -1) if ((fd = server_start(path)) == -1)
goto failed; goto start_failed;
break; goto server_started;
default:
goto failed;
} }
goto not_found;
} }
server_started:
if ((mode = fcntl(fd, F_GETFL)) == -1) if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
return (fd); if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
failed:
close(fd);
return (-1);
}
/* Client main loop. */
int
client_main(int argc, char **argv, int flags)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data cmddata;
int cmdflags, fd;
enum msgtype msg;
char *cause;
/* Set up the initial command. */
cmdflags = 0;
if (shell_cmd != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
} else {
msg = MSG_COMMAND;
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
log_warnx("%s", cause);
return (1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST;
}
cmd_list_free(cmdlist);
}
/*
* Check if this could be a nested session, if the command can't nest:
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shell_cmd == NULL && environ_path != NULL &&
cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
log_warnx("sessions should be nested with care. "
"unset $TMUX to force.");
return (1);
}
/* Initialise the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
log_warn("failed to connect to server");
return (1);
}
/* Set process title, log and signals now this is the client. */
#ifdef HAVE_SETPROCTITLE
setproctitle("client (%s)", socket_path);
#endif
logfile("client");
/* Create imsg. */
imsg_init(&client_ibuf, fd); imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
/* Establish signal handlers. */
set_signals(client_signal);
/* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON) if (cmdflags & CMD_SENDENVIRON)
client_send_environ(); client_send_environ();
client_send_identify(flags); client_send_identify(flags);
/* Send first command. */ return (&client_ibuf);
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
cmddata.pid = environ_pid;
cmddata.idx = environ_idx;
/* Prepare command for server. */ start_failed:
cmddata.argc = argc; log_warnx("server failed to start");
if (cmd_pack_argv( return (NULL);
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
log_warnx("command too long");
return (1);
}
client_write_server(msg, &cmddata, sizeof cmddata); not_found:
} else if (msg == MSG_SHELL) log_warn("server not found");
client_write_server(msg, NULL, 0); return (NULL);
/* Set the event and dispatch. */
client_update_event();
event_dispatch();
/* Print the exit message, if any, and exit. */
if (client_attached && client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exitmsg);
return (client_exitval);
} }
/* Send identify message to server with the file descriptors. */
void void
client_send_identify(int flags) client_send_identify(int flags)
{ {
@@ -227,16 +137,13 @@ client_send_identify(int flags)
if ((fd = dup(STDOUT_FILENO)) == -1) if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
imsg_compose(&client_ibuf, imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
if ((fd = dup(STDERR_FILENO)) == -1) if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
imsg_compose(&client_ibuf, imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
} }
/* Forward entire environment to server. */
void void
client_send_environ(void) client_send_environ(void)
{ {
@@ -250,14 +157,12 @@ client_send_environ(void)
} }
} }
/* Write a message to the server without a file descriptor. */
void void
client_write_server(enum msgtype type, void *buf, size_t len) client_write_server(enum msgtype type, void *buf, size_t len)
{ {
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
} }
/* Update client event based on whether it needs to read or read and write. */
void void
client_update_event(void) client_update_event(void)
{ {
@@ -267,74 +172,91 @@ client_update_event(void)
events = EV_READ; events = EV_READ;
if (client_ibuf.w.queued > 0) if (client_ibuf.w.queued > 0)
events |= EV_WRITE; events |= EV_WRITE;
event_set( event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
&client_event, client_ibuf.fd, events, client_callback, shell_cmd);
event_add(&client_event, NULL); event_add(&client_event, NULL);
} }
/* Callback to handle signals in the client. */ __dead void
client_main(void)
{
logfile("client");
/* Note: event_init() has already been called. */
/* Set up signals. */
set_signals(client_signal);
/*
* Send a resize message immediately in case the terminal size has
* changed between the identify message to the server and the MSG_READY
* telling us to move into the client code.
*/
client_write_server(MSG_RESIZE, NULL, 0);
/*
* imsg_read in the first client poll loop (before the terminal has
* been initialised) may have read messages into the buffer after the
* MSG_READY switched to here. Process anything outstanding now to
* avoid hanging waiting for messages that have already arrived.
*/
if (client_dispatch() != 0)
goto out;
/* Set the event and dispatch. */
client_update_event();
event_dispatch();
out:
/* Print the exit message, if any, and exit. */
if (client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exitmsg);
exit(client_exitval);
}
/* ARGSUSED */ /* ARGSUSED */
void void
client_signal(int sig, unused short events, unused void *data) client_signal(int sig, unused short events, unused void *data)
{ {
struct sigaction sigact; struct sigaction sigact;
int status;
if (!client_attached) { switch (sig) {
switch (sig) { case SIGHUP:
case SIGCHLD: client_exitmsg = "lost tty";
waitpid(WAIT_ANY, &status, WNOHANG); client_exitval = 1;
break; client_write_server(MSG_EXITING, NULL, 0);
case SIGTERM: break;
event_loopexit(NULL); case SIGTERM:
break; client_exitmsg = "terminated";
} client_exitval = 1;
} else { client_write_server(MSG_EXITING, NULL, 0);
switch (sig) { break;
case SIGHUP: case SIGWINCH:
client_exitmsg = "lost tty"; client_write_server(MSG_RESIZE, NULL, 0);
client_exitval = 1; break;
client_write_server(MSG_EXITING, NULL, 0); case SIGCONT:
break; memset(&sigact, 0, sizeof sigact);
case SIGTERM: sigemptyset(&sigact.sa_mask);
client_exitmsg = "terminated"; sigact.sa_flags = SA_RESTART;
client_exitval = 1; sigact.sa_handler = SIG_IGN;
client_write_server(MSG_EXITING, NULL, 0); if (sigaction(SIGTSTP, &sigact, NULL) != 0)
break; fatal("sigaction failed");
case SIGWINCH: client_write_server(MSG_WAKEUP, NULL, 0);
client_write_server(MSG_RESIZE, NULL, 0); break;
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_write_server(MSG_WAKEUP, NULL, 0);
break;
}
} }
client_update_event(); client_update_event();
} }
/* Callback for client imsg read events. */
/* ARGSUSED */ /* ARGSUSED */
void void
client_callback(unused int fd, short events, void *data) client_callback(unused int fd, short events, unused void *data)
{ {
ssize_t n; ssize_t n;
int retval;
if (events & EV_READ) { if (events & EV_READ) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
goto lost_server; goto lost_server;
if (client_attached) if (client_dispatch() != 0) {
retval = client_dispatch_attached();
else
retval = client_dispatch_wait(data);
if (retval != 0) {
event_loopexit(NULL); event_loopexit(NULL);
return; return;
} }
@@ -354,76 +276,8 @@ lost_server:
event_loopexit(NULL); event_loopexit(NULL);
} }
/* Dispatch imsgs when in wait state (before MSG_READY). */
int int
client_dispatch_wait(void *data) client_dispatch(void)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
const char *shellcmd = data;
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof exitdata) {
if (datalen != 0)
fatalx("bad MSG_EXIT size");
} else {
memcpy(&exitdata, imsg.data, sizeof exitdata);
client_exitval = exitdata.retcode;
}
imsg_free(&imsg);
return (-1);
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
client_attached = 1;
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
client_exitval = 1;
imsg_free(&imsg);
return (-1);
case MSG_SHELL:
if (datalen != sizeof shelldata)
fatalx("bad MSG_SHELL size");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
clear_signals(0);
shell_exec(shelldata.shell, shellcmd);
/* NOTREACHED */
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
}
/* Dispatch imsgs in attached state (after MSG_READY). */
/* ARGSUSED */
int
client_dispatch_attached(void)
{ {
struct imsg imsg; struct imsg imsg;
struct msg_lock_data lockdata; struct msg_lock_data lockdata;
@@ -447,8 +301,7 @@ client_dispatch_attached(void)
client_exitmsg = "detached"; client_exitmsg = "detached";
break; break;
case MSG_EXIT: case MSG_EXIT:
if (datalen != 0 && if (datalen != 0)
datalen != sizeof (struct msg_exit_data))
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-attach-session.c,v 1.37 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd-attach-session.c,v 1.36 2010-02-08 18:27:34 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
char *overrides, *cause; char *overrides, *cause;
u_int i; u_int i;
if (RB_EMPTY(&sessions)) { if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions"); ctx->error(ctx, "no sessions");
return (-1); return (-1);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-session.c,v 1.17 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd-choose-session.c,v 1.15 2009-11-14 17:56:39 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl; struct winlink *wl;
struct session *s; struct session *s;
struct session_group *sg; struct session_group *sg;
u_int idx, sgidx, cur; u_int i, idx, cur;
char tmp[64]; char tmp[64];
if (ctx->curclient == NULL) { if (ctx->curclient == NULL) {
@@ -70,7 +70,10 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0); return (0);
cur = idx = 0; cur = idx = 0;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (s == ctx->curclient->session) if (s == ctx->curclient->session)
cur = idx; cur = idx;
idx++; idx++;
@@ -79,11 +82,11 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if (sg == NULL) if (sg == NULL)
*tmp = '\0'; *tmp = '\0';
else { else {
sgidx = session_group_index(sg); idx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx); xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
} }
window_choose_add(wl->window->active, s->idx, window_choose_add(wl->window->active, i,
"%s: %u windows [%ux%u]%s%s", s->name, "%s: %u windows [%ux%u]%s%s", s->name,
winlink_count(&s->windows), s->sx, s->sy, winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
@@ -117,7 +120,9 @@ cmd_choose_session_callback(void *data, int idx)
if (cdata->client->flags & CLIENT_DEAD) if (cdata->client->flags & CLIENT_DEAD)
return; return;
s = session_find_by_index(idx); if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1)
return;
s = ARRAY_ITEM(&sessions, idx);
if (s == NULL) if (s == NULL)
return; return;
template = cmd_template_replace(cdata->template, s->name, 1); template = cmd_template_replace(cdata->template, s->name, 1);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-window.c,v 1.24 2010-12-22 15:28:50 tcunha Exp $ */ /* $Id: cmd-choose-window.c,v 1.22 2010-06-22 23:26:18 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -87,8 +87,6 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
flag = '!'; flag = '!';
else if (wm->flags & WINLINK_CONTENT) else if (wm->flags & WINLINK_CONTENT)
flag = '+'; flag = '+';
else if (wm->flags & WINLINK_SILENCE)
flag = '~';
else if (wm == s->curw) else if (wm == s->curw)
flag = '*'; flag = '*';
else if (wm == TAILQ_FIRST(&s->lastw)) else if (wm == TAILQ_FIRST(&s->lastw))
@@ -129,19 +127,20 @@ void
cmd_choose_window_callback(void *data, int idx) cmd_choose_window_callback(void *data, int idx)
{ {
struct cmd_choose_window_data *cdata = data; struct cmd_choose_window_data *cdata = data;
struct session *s = cdata->session;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_ctx ctx; struct cmd_ctx ctx;
char *target, *template, *cause; char *target, *template, *cause;
if (idx == -1) if (idx == -1)
return; return;
if (!session_alive(s))
return;
if (cdata->client->flags & CLIENT_DEAD) if (cdata->client->flags & CLIENT_DEAD)
return; return;
if (cdata->session->flags & SESSION_DEAD)
return;
if (cdata->client->session != cdata->session)
return;
xasprintf(&target, "%s:%d", s->name, idx); xasprintf(&target, "%s:%d", cdata->session->name, idx);
template = cmd_template_replace(cdata->template, target, 1); template = cmd_template_replace(cdata->template, target, 1);
xfree(target); xfree(target);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-copy-mode.c,v 1.28 2010-08-11 22:18:28 tcunha Exp $ */ /* $Id: cmd-copy-mode.c,v 1.27 2010-04-05 05:11:42 micahcowan Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -62,8 +62,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1); return (-1);
if (window_pane_set_mode(wp, &window_copy_mode) != 0) window_pane_set_mode(wp, &window_copy_mode);
return (0);
window_copy_init_from_pane(wp); window_copy_init_from_pane(wp);
if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u'))
window_copy_pageup(wp); window_copy_pageup(wp);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-find-window.c,v 1.15 2010-12-22 15:28:50 tcunha Exp $ */ /* $Id: cmd-find-window.c,v 1.14 2009-11-14 17:56:39 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,7 +30,6 @@
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *); int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_find_window_callback(void *, int); void cmd_find_window_callback(void *, int);
void cmd_find_window_free(void *);
const struct cmd_entry cmd_find_window_entry = { const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw", "find-window", "findw",
@@ -44,7 +43,7 @@ const struct cmd_entry cmd_find_window_entry = {
}; };
struct cmd_find_window_data { struct cmd_find_window_data {
struct session *session; u_int session;
}; };
int int
@@ -135,11 +134,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->session = s; if (session_index(s, &cdata->session) != 0)
cdata->session->references++; fatalx("session not found");
window_choose_ready(wl->window->active, window_choose_ready(
0, cmd_find_window_callback, cmd_find_window_free, cdata); wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
out: out:
ARRAY_FREE(&list_idx); ARRAY_FREE(&list_idx);
@@ -152,24 +151,12 @@ void
cmd_find_window_callback(void *data, int idx) cmd_find_window_callback(void *data, int idx)
{ {
struct cmd_find_window_data *cdata = data; struct cmd_find_window_data *cdata = data;
struct session *s = cdata->session; struct session *s;
if (idx == -1) if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
return; s = ARRAY_ITEM(&sessions, cdata->session);
if (!session_alive(s)) if (s != NULL && session_select(s, idx) == 0)
return; server_redraw_session(s);
if (session_select(s, idx) == 0) {
server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
} }
} }
void
cmd_find_window_free(void *data)
{
struct cmd_find_window_data *cdata = data;
cdata->session->references--;
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-if-shell.c,v 1.10 2010-08-09 21:44:25 tcunha Exp $ */ /* $Id: cmd-if-shell.c,v 1.9 2010-07-17 14:36:40 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -109,7 +109,8 @@ cmd_if_shell_free(void *data)
if (ctx->cmdclient != NULL) { if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--; ctx->cmdclient->references--;
exitdata.retcode = ctx->cmdclient->retcode; exitdata.retcode = ctx->cmdclient->retcode;
ctx->cmdclient->flags |= CLIENT_EXIT; server_write_client(
ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
} }
if (ctx->curclient != NULL) if (ctx->curclient != NULL)
ctx->curclient->references--; ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-join-pane.c,v 1.5 2010-08-11 22:17:32 tcunha Exp $ */ /* $Id: cmd-join-pane.c,v 1.4 2010-04-09 07:09:37 micahcowan Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,7 +44,7 @@ struct cmd_join_pane_data {
const struct cmd_entry cmd_join_pane_entry = { const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp", "join-pane", "joinp",
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane] [command]",
0, "", 0, "",
cmd_join_pane_init, cmd_join_pane_init,
cmd_join_pane_parse, cmd_join_pane_parse,

View File

@@ -1,58 +0,0 @@
/* $Id: cmd-last-pane.c,v 1.1 2010-10-24 01:34:30 tcunha Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Move to last pane.
*/
int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp",
CMD_TARGET_WINDOW_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_last_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
if (w->last == NULL) {
ctx->error(ctx, "no last pane");
return (-1);
}
window_set_active_pane(w, w->last);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-keys.c,v 1.25 2010-10-24 01:31:57 tcunha Exp $ */ /* $Id: cmd-list-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -80,11 +80,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
if (used >= sizeof tmp) if (used >= sizeof tmp)
continue; continue;
} }
if (bd->can_repeat) {
used = strlcat(tmp, "(repeat) ", sizeof tmp);
if (used >= sizeof tmp)
continue;
}
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
ctx->print(ctx, "%s", tmp); ctx->print(ctx, "%s", tmp);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-panes.c,v 1.6 2010-12-06 21:56:32 nicm Exp $ */ /* $Id: cmd-list-panes.c,v 1.4 2009-12-04 22:14:47 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -65,10 +65,8 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
size += gd->hsize * sizeof *gd->linedata; size += gd->hsize * sizeof *gd->linedata;
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s", ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
n++; n++;
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-sessions.c,v 1.26 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd-list-sessions.c,v 1.25 2009-11-28 14:50:36 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,10 +46,14 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
struct session *s; struct session *s;
struct session_group *sg; struct session_group *sg;
char *tim, tmp[64]; char *tim, tmp[64];
u_int idx; u_int i, idx;
time_t t; time_t t;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
sg = session_group_find(s); sg = session_group_find(s);
if (sg == NULL) if (sg == NULL)
*tmp = '\0'; *tmp = '\0';

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.44 2010-12-06 21:56:32 nicm Exp $ */ /* $Id: cmd-list-windows.c,v 1.43 2010-07-02 02:54:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -51,10 +51,10 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1); return (-1);
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ctx->print(ctx, "%d: %s [%ux%u]",
wl->idx, wl->window->name, wl->window->sx, wl->window->sy);
layout = layout_dump(wl->window); layout = layout_dump(wl->window);
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", ctx->print(ctx, " layout: %s", layout);
wl->idx, wl->window->name, wl->window->sx, wl->window->sy,
layout, wl == s->curw ? " (active)" : "");
xfree(layout); xfree(layout);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list.c,v 1.10 2010-12-06 21:48:56 nicm Exp $ */ /* $Id: cmd-list.c,v 1.9 2010-07-02 02:43:01 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,9 +29,7 @@ cmd_list_parse(int argc, char **argv, char **cause)
struct cmd *cmd; struct cmd *cmd;
int i, lastsplit; int i, lastsplit;
size_t arglen, new_argc; size_t arglen, new_argc;
char **copy_argv, **new_argv; char **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xmalloc(sizeof *cmdlist); cmdlist = xmalloc(sizeof *cmdlist);
cmdlist->references = 1; cmdlist->references = 1;
@@ -39,18 +37,18 @@ cmd_list_parse(int argc, char **argv, char **cause)
lastsplit = 0; lastsplit = 0;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]); arglen = strlen(argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';') if (arglen == 0 || argv[i][arglen - 1] != ';')
continue; continue;
copy_argv[i][arglen - 1] = '\0'; argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') { if (arglen > 1 && argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';'; argv[i][arglen - 2] = ';';
continue; continue;
} }
new_argc = i - lastsplit; new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit; new_argv = argv + lastsplit;
if (arglen != 1) if (arglen != 1)
new_argc++; new_argc++;
@@ -63,18 +61,16 @@ cmd_list_parse(int argc, char **argv, char **cause)
} }
if (lastsplit != argc) { if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause); cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
if (cmd == NULL) if (cmd == NULL)
goto bad; goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
} }
cmd_free_argv(argc, copy_argv);
return (cmdlist); return (cmdlist);
bad: bad:
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL); return (NULL);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-load-buffer.c,v 1.18 2010-12-22 15:28:50 tcunha Exp $ */ /* $Id: cmd-load-buffer.c,v 1.16 2010-07-02 02:52:13 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -31,7 +31,6 @@
*/ */
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_load_buffer_callback(struct client *, void *);
const struct cmd_entry cmd_load_buffer_entry = { const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb", "load-buffer", "loadb",
@@ -44,56 +43,37 @@ const struct cmd_entry cmd_load_buffer_entry = {
cmd_buffer_print cmd_buffer_print
}; };
struct cmd_load_buffer_cdata {
struct session *session;
int buffer;
};
int int
cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_buffer_data *data = self->data; struct cmd_buffer_data *data = self->data;
struct cmd_load_buffer_cdata *cdata; struct session *s;
struct session *s; FILE *f, *close_f;
struct client *c = ctx->cmdclient; char *pdata, *new_pdata;
FILE *f; size_t psize;
char *pdata, *new_pdata; u_int limit;
size_t psize; int ch;
u_int limit;
int ch;
if ((s = cmd_find_session(ctx, data->target)) == NULL) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
if (strcmp(data->arg, "-") == 0) { if (strcmp(data->arg, "-") == 0 ) {
if (c == NULL) { if (ctx->cmdclient == NULL) {
ctx->error(ctx, "%s: can't read from stdin", data->arg); ctx->error(ctx, "%s: can't read from stdin", data->arg);
return (-1); return (-1);
} }
if (c->flags & CLIENT_TERMINAL) { f = ctx->cmdclient->stdin_file;
if (isatty(fileno(ctx->cmdclient->stdin_file))) {
ctx->error(ctx, "%s: stdin is a tty", data->arg); ctx->error(ctx, "%s: stdin is a tty", data->arg);
return (-1); return (-1);
} }
if (c->stdin_fd == -1) { close_f = NULL;
ctx->error(ctx, "%s: can't read from stdin", data->arg); } else {
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1); return (-1);
} }
close_f = f;
cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
cdata->buffer = data->buffer;
c->stdin_data = cdata;
c->stdin_callback = cmd_load_buffer_callback;
c->references++;
bufferevent_enable(c->stdin_event, EV_READ);
return (1);
}
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
} }
pdata = NULL; pdata = NULL;
@@ -114,8 +94,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
if (pdata != NULL) if (pdata != NULL)
pdata[psize] = '\0'; pdata[psize] = '\0';
fclose(f); if (close_f != NULL)
f = NULL; fclose(close_f);
limit = options_get_number(&s->options, "buffer-limit"); limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) { if (data->buffer == -1) {
@@ -124,7 +104,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) { if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer); ctx->error(ctx, "no buffer %d", data->buffer);
return (-1); goto error;
} }
return (0); return (0);
@@ -132,54 +112,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
error: error:
if (pdata != NULL) if (pdata != NULL)
xfree(pdata); xfree(pdata);
if (f != NULL) if (close_f != NULL)
fclose(f); fclose(close_f);
return (-1); return (-1);
} }
void
cmd_load_buffer_callback(struct client *c, void *data)
{
struct cmd_load_buffer_cdata *cdata = data;
struct session *s = cdata->session;
char *pdata;
size_t psize;
u_int limit;
/*
* Event callback has already checked client is not dead and reduced
* its reference count. But tell it to exit.
*/
c->flags |= CLIENT_EXIT;
/* Does the target session still exist? */
if (!session_alive(s))
goto out;
psize = EVBUFFER_LENGTH(c->stdin_event->input);
if (psize == 0)
goto out;
pdata = malloc(psize + 1);
if (pdata == NULL)
goto out;
bufferevent_read(c->stdin_event, pdata, psize);
pdata[psize] = '\0';
limit = options_get_number(&s->options, "buffer-limit");
if (cdata->buffer == -1) {
paste_add(&s->buffers, pdata, psize, limit);
goto out;
}
if (paste_replace(&s->buffers, cdata->buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */
evbuffer_add_printf(
c->stderr_event->output, "no buffer %d\n", cdata->buffer);
bufferevent_enable(c->stderr_event, EV_WRITE);
goto out;
}
out:
cdata->session->references--;
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.80 2010-12-22 15:31:00 tcunha Exp $ */ /* $Id: cmd-new-session.c,v 1.78 2010-07-02 02:49:19 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -122,7 +122,7 @@ int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_new_session_data *data = self->data; struct cmd_new_session_data *data = self->data;
struct session *s, *old_s, *groupwith; struct session *s, *groupwith;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
struct environ env; struct environ env;
@@ -279,16 +279,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if (!detached) { if (!detached) {
if (ctx->cmdclient != NULL) { if (ctx->cmdclient != NULL) {
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
old_s = ctx->cmdclient->session;
if (old_s != NULL)
ctx->cmdclient->last_session = old_s;
ctx->cmdclient->session = s; ctx->cmdclient->session = s;
server_redraw_client(ctx->cmdclient); server_redraw_client(ctx->cmdclient);
} else { } else {
old_s = ctx->curclient->session;
if (old_s != NULL)
ctx->curclient->last_session = old_s;
ctx->curclient->session = s; ctx->curclient->session = s;
server_redraw_client(ctx->curclient); server_redraw_client(ctx->curclient);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-paste-buffer.c,v 1.29 2010-08-11 22:17:32 tcunha Exp $ */ /* $Id: cmd-paste-buffer.c,v 1.28 2010-06-06 00:03:02 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,7 +45,7 @@ size_t cmd_paste_buffer_print(struct cmd *, char *, size_t);
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb", "paste-buffer", "pasteb",
"[-dr] [-s separator] [-b buffer-index] [-t target-pane]", "[-dr] [-s separator] [-b buffer-index] [-t target-window]",
0, "", 0, "",
cmd_paste_buffer_init, cmd_paste_buffer_init,
cmd_paste_buffer_parse, cmd_paste_buffer_parse,

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-pipe-pane.c,v 1.15 2010-10-24 00:45:57 tcunha Exp $ */ /* $Id: cmd-pipe-pane.c,v 1.13 2010-06-15 20:25:40 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -96,7 +96,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
case 0: case 0:
/* Child process. */ /* Child process. */
close(pipe_fd[0]); close(pipe_fd[0]);
clear_signals(1); clear_signals();
if (dup2(pipe_fd[1], STDIN_FILENO) == -1) if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1); _exit(1);
@@ -111,8 +111,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd); close(null_fd);
closefrom(STDERR_FILENO + 1);
command = status_replace(c, NULL, data->arg, time(NULL), 0); command = status_replace(c, NULL, data->arg, time(NULL), 0);
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
_exit(1); _exit(1);
@@ -131,6 +129,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
return (0); return (0);
} }
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-rename-session.c,v 1.21 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd-rename-session.c,v 1.19 2009-11-14 17:56:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,18 +45,11 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct session *s;
if (data->arg != NULL && session_find(data->arg) != NULL) {
ctx->error(ctx, "duplicate session: %s", data->arg);
return (-1);
}
if ((s = cmd_find_session(ctx, data->target)) == NULL) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
RB_REMOVE(sessions, &sessions, s);
xfree(s->name); xfree(s->name);
s->name = xstrdup(data->arg); s->name = xstrdup(data->arg);
RB_INSERT(sessions, &sessions, s);
server_status_session(s); server_status_session(s);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-run-shell.c,v 1.9 2010-08-09 21:44:25 tcunha Exp $ */ /* $Id: cmd-run-shell.c,v 1.8 2010-07-17 14:36:40 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -131,10 +131,13 @@ cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx; struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
if (ctx->cmdclient != NULL) { if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--; ctx->cmdclient->references--;
ctx->cmdclient->flags |= CLIENT_EXIT; exitdata.retcode = ctx->cmdclient->retcode;
server_write_client(
ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
} }
if (ctx->curclient != NULL) if (ctx->curclient != NULL)
ctx->curclient->references--; ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-save-buffer.c,v 1.12 2010-08-09 21:44:25 tcunha Exp $ */ /* $Id: cmd-save-buffer.c,v 1.11 2010-07-02 02:52:13 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -47,8 +47,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_buffer_data *data = self->data; struct cmd_buffer_data *data = self->data;
struct session *s; struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
mode_t mask; mode_t mask;
FILE *f; FILE *f, *close_f;
if ((s = cmd_find_session(ctx, data->target)) == NULL) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
@@ -70,8 +70,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "%s: can't write to stdout", data->arg); ctx->error(ctx, "%s: can't write to stdout", data->arg);
return (-1); return (-1);
} }
bufferevent_write( f = ctx->cmdclient->stdout_file;
ctx->cmdclient->stdout_event, pb->data, pb->size); close_f = NULL;
} else { } else {
mask = umask(S_IRWXG | S_IRWXO); mask = umask(S_IRWXG | S_IRWXO);
if (cmd_check_flag(data->chflags, 'a')) if (cmd_check_flag(data->chflags, 'a'))
@@ -83,13 +83,17 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1); return (-1);
} }
if (fwrite(pb->data, 1, pb->size, f) != pb->size) { close_f = f;
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
} }
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
if (close_f != NULL)
fclose(close_f);
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-server-info.c,v 1.38 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd-server-info.c,v 1.37 2009-12-10 16:59:02 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,6 +81,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
else else
ctx->print(ctx, "configuration file not specified"); ctx->print(ctx, "configuration file not specified");
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
ctx->print(ctx, "%u clients, %u sessions",
ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions));
ctx->print(ctx, "%s", ""); ctx->print(ctx, "%s", "");
ctx->print(ctx, "Clients:"); ctx->print(ctx, "Clients:");
@@ -99,14 +101,19 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
ctx->print(ctx, "Sessions: [%zu/%zu]", ctx->print(ctx, "Sessions: [%zu/%zu]",
sizeof (struct grid_cell), sizeof (struct grid_utf8)); sizeof (struct grid_cell), sizeof (struct grid_utf8));
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
t = s->creation_time.tv_sec; t = s->creation_time.tv_sec;
tim = ctime(&t); tim = ctime(&t);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
"[flags=0x%x]", s->idx, s->name, "[flags=0x%x, references=%u]", i, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags); winlink_count(&s->windows), tim, s->sx, s->sy, s->flags,
s->references);
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window; w = wl->window;
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.102 2010-12-22 15:23:59 tcunha Exp $ */ /* $Id: cmd-set-option.c,v 1.98 2010-07-02 02:45:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -75,7 +75,6 @@ const char *set_option_bell_action_list[] = {
const struct set_option_entry set_option_table[] = { const struct set_option_entry set_option_table[] = {
{ "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL },
{ "quiet", SET_OPTION_FLAG, 0, 0, NULL }, { "quiet", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL } { NULL, 0, 0, 0, NULL }
}; };
@@ -88,7 +87,6 @@ const struct set_option_entry set_session_option_table[] = {
{ "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL },
{ "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-shell", SET_OPTION_STRING, 0, 0, NULL },
{ "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL },
{ "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL },
{ "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL }, { "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL },
{ "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL },
@@ -136,7 +134,6 @@ const struct set_option_entry set_session_option_table[] = {
{ "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-silence", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL } { NULL, 0, 0, 0, NULL }
}; };
@@ -158,9 +155,6 @@ const struct set_option_entry set_window_option_table[] = {
{ "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL },
{ "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL},
{ "other-pane-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "other-pane-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL },
{ "utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL },
@@ -299,7 +293,6 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
*/ */
if (strcmp(entry->name, "status-left") == 0 || if (strcmp(entry->name, "status-left") == 0 ||
strcmp(entry->name, "status-right") == 0 || strcmp(entry->name, "status-right") == 0 ||
strcmp(entry->name, "status") == 0 ||
strcmp(entry->name, "set-titles-string") == 0 || strcmp(entry->name, "set-titles-string") == 0 ||
strcmp(entry->name, "window-status-format") == 0) { strcmp(entry->name, "window-status-format") == 0) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-string.c,v 1.32 2010-12-13 22:53:56 nicm Exp $ */ /* $Id: cmd-string.c,v 1.31 2010-02-26 13:27:38 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -247,10 +247,9 @@ error:
char * char *
cmd_string_variable(const char *s, size_t *p) cmd_string_variable(const char *s, size_t *p)
{ {
int ch, fch; int ch, fch;
char *buf, *t; char *buf, *t;
size_t len; size_t len;
struct environ_entry *envent;
#define cmd_string_first(ch) ((ch) == '_' || \ #define cmd_string_first(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
@@ -302,11 +301,12 @@ cmd_string_variable(const char *s, size_t *p)
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
envent = environ_find(&global_environ, buf); if ((t = getenv(buf)) == NULL) {
xfree(buf); xfree(buf);
if (envent == NULL)
return (xstrdup("")); return (xstrdup(""));
return (xstrdup(envent->value)); }
xfree(buf);
return (xstrdup(t));
error: error:
if (buf != NULL) if (buf != NULL)
@@ -317,17 +317,15 @@ error:
char * char *
cmd_string_expand_tilde(const char *s, size_t *p) cmd_string_expand_tilde(const char *s, size_t *p)
{ {
struct passwd *pw; struct passwd *pw;
struct environ_entry *envent; char *home, *path, *username;
char *home, *path, *username;
home = NULL; home = NULL;
if (cmd_string_getc(s, p) == '/') { if (cmd_string_getc(s, p) == '/') {
envent = environ_find(&global_environ, "HOME"); if ((home = getenv("HOME")) == NULL || *home == '\0') {
if (envent != NULL && *envent->value != '\0') if ((pw = getpwuid(getuid())) != NULL)
home = envent->value; home = pw->pw_dir;
else if ((pw = getpwuid(getuid())) != NULL) }
home = pw->pw_dir;
} else { } else {
cmd_string_ungetc(p); cmd_string_ungetc(p);
if ((username = cmd_string_string(s, p, '/', 0)) == NULL) if ((username = cmd_string_string(s, p, '/', 0)) == NULL)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-switch-client.c,v 1.23 2010-12-22 15:31:00 tcunha Exp $ */ /* $Id: cmd-switch-client.c,v 1.19 2010-01-25 17:12:44 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,7 +27,6 @@
* Switch client to a different session. * Switch client to a different session.
*/ */
void cmd_switch_client_init(struct cmd *, int);
int cmd_switch_client_parse(struct cmd *, int, char **, char **); int cmd_switch_client_parse(struct cmd *, int, char **, char **);
int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
void cmd_switch_client_free(struct cmd *); void cmd_switch_client_free(struct cmd *);
@@ -36,83 +35,36 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t);
struct cmd_switch_client_data { struct cmd_switch_client_data {
char *name; char *name;
char *target; char *target;
int flag_last;
int flag_next;
int flag_previous;
}; };
const struct cmd_entry cmd_switch_client_entry = { const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc", "switch-client", "switchc",
"[-lnp] [-c target-client] [-t target-session]", "[-c target-client] [-t target-session]",
0, "", 0, "",
cmd_switch_client_init, NULL,
cmd_switch_client_parse, cmd_switch_client_parse,
cmd_switch_client_exec, cmd_switch_client_exec,
cmd_switch_client_free, cmd_switch_client_free,
cmd_switch_client_print cmd_switch_client_print
}; };
void
cmd_switch_client_init(struct cmd *self, int key)
{
struct cmd_switch_client_data *data;
self->data = data = xmalloc(sizeof *data);
data->name = NULL;
data->target = NULL;
data->flag_last = 0;
data->flag_next = 0;
data->flag_previous = 0;
switch (key) {
case '(':
data->flag_previous = 1;
break;
case ')':
data->flag_next = 1;
break;
case 'L':
data->flag_last = 1;
break;
}
}
int int
cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause)
{ {
struct cmd_switch_client_data *data; struct cmd_switch_client_data *data;
int opt; int opt;
self->entry->init(self, KEYC_NONE); self->data = data = xmalloc(sizeof *data);
data = self->data; data->name = NULL;
data->target = NULL;
while ((opt = getopt(argc, argv, "c:lnpt:")) != -1) { while ((opt = getopt(argc, argv, "c:t:")) != -1) {
switch (opt) { switch (opt) {
case 'c': case 'c':
if (data->name == NULL) if (data->name == NULL)
data->name = xstrdup(optarg); data->name = xstrdup(optarg);
break; break;
case 'l':
if (data->flag_next || data->flag_previous ||
data->target != NULL)
goto usage;
data->flag_last = 1;
break;
case 'n':
if (data->flag_previous || data->flag_last ||
data->target != NULL)
goto usage;
data->flag_next = 1;
break;
case 'p':
if (data->flag_next || data->flag_last ||
data->target != NULL)
goto usage;
data->flag_next = 1;
break;
case 't': case 't':
if (data->flag_next || data->flag_previous)
goto usage;
if (data->target == NULL) if (data->target == NULL)
data->target = xstrdup(optarg); data->target = xstrdup(optarg);
break; break;
@@ -146,36 +98,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((c = cmd_find_client(ctx, data->name)) == NULL) if ((c = cmd_find_client(ctx, data->name)) == NULL)
return (-1); return (-1);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
s = NULL;
if (data->flag_next) {
if ((s = session_next_session(c->session)) == NULL) {
ctx->error(ctx, "can't find next session");
return (-1);
}
} else if (data->flag_previous) {
if ((s = session_previous_session(c->session)) == NULL) {
ctx->error(ctx, "can't find previous session");
return (-1);
}
} else if (data->flag_last) {
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
if (s == NULL) {
ctx->error(ctx, "can't find last session");
return (-1);
}
} else
s = cmd_find_session(ctx, data->target);
if (s == NULL)
return (-1); return (-1);
if (c->session != NULL)
c->last_session = c->session;
c->session = s; c->session = s;
recalculate_sizes(); recalculate_sizes();
server_check_unattached();
server_redraw_client(c); server_redraw_client(c);
return (0); return (0);
@@ -202,12 +130,6 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len)
off += xsnprintf(buf, len, "%s", self->entry->name); off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL) if (data == NULL)
return (off); return (off);
if (off < len && data->flag_last)
off += xsnprintf(buf + off, len - off, "%s", " -l");
if (off < len && data->flag_next)
off += xsnprintf(buf + off, len - off, "%s", " -n");
if (off < len && data->flag_previous)
off += xsnprintf(buf + off, len - off, "%s", " -p");
if (off < len && data->name != NULL) if (off < len && data->name != NULL)
off += cmd_prarg(buf + off, len - off, " -c ", data->name); off += cmd_prarg(buf + off, len - off, " -c ", data->name);
if (off < len && data->target != NULL) if (off < len && data->target != NULL)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-unbind-key.c,v 1.23 2010-12-06 21:51:02 nicm Exp $ */ /* $Id: cmd-unbind-key.c,v 1.22 2010-01-25 17:12:44 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,14 +33,13 @@ int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *);
struct cmd_unbind_key_data { struct cmd_unbind_key_data {
int key; int key;
int flag_all;
int command_key; int command_key;
char *tablename; char *tablename;
}; };
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind", "unbind-key", "unbind",
"[-acn] [-t key-table] key", "[-cn] [-t key-table] key",
0, "", 0, "",
NULL, NULL,
cmd_unbind_key_parse, cmd_unbind_key_parse,
@@ -56,15 +55,11 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
int opt, no_prefix = 0; int opt, no_prefix = 0;
self->data = data = xmalloc(sizeof *data); self->data = data = xmalloc(sizeof *data);
data->flag_all = 0;
data->command_key = 0; data->command_key = 0;
data->tablename = NULL; data->tablename = NULL;
while ((opt = getopt(argc, argv, "acnt:")) != -1) { while ((opt = getopt(argc, argv, "cnt:")) != -1) {
switch (opt) { switch (opt) {
case 'a':
data->flag_all = 1;
break;
case 'c': case 'c':
data->command_key = 1; data->command_key = 1;
break; break;
@@ -81,20 +76,15 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (data->flag_all && (argc != 0 || data->tablename)) if (argc != 1)
goto usage;
if (!data->flag_all && argc != 1)
goto usage; goto usage;
if (!data->flag_all) { if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) {
data->key = key_string_lookup_string(argv[0]); xasprintf(cause, "unknown key: %s", argv[0]);
if (data->key == KEYC_NONE) { goto error;
xasprintf(cause, "unknown key: %s", argv[0]);
goto error;
}
if (!no_prefix)
data->key |= KEYC_PREFIX;
} }
if (!no_prefix)
data->key |= KEYC_PREFIX;
return (0); return (0);
@@ -110,23 +100,13 @@ int
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{ {
struct cmd_unbind_key_data *data = self->data; struct cmd_unbind_key_data *data = self->data;
struct key_binding *bd;
if (data == NULL) if (data == NULL)
return (0); return (0);
if (data->flag_all) { if (data->tablename != NULL)
while (!SPLAY_EMPTY(&key_bindings)) { return (cmd_unbind_key_table(self, ctx));
bd = SPLAY_ROOT(&key_bindings);
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
cmd_list_free(bd->cmdlist);
xfree(bd);
}
} else {
if (data->tablename != NULL)
return (cmd_unbind_key_table(self, ctx));
key_bindings_remove(data->key); key_bindings_remove(data->key);
}
return (0); return (0);
} }

78
cmd.c
View File

@@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.146 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: cmd.c,v 1.142 2010-07-17 14:38:13 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,7 +53,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_kill_server_entry, &cmd_kill_server_entry,
&cmd_kill_session_entry, &cmd_kill_session_entry,
&cmd_kill_window_entry, &cmd_kill_window_entry,
&cmd_last_pane_entry,
&cmd_last_window_entry, &cmd_last_window_entry,
&cmd_link_window_entry, &cmd_link_window_entry,
&cmd_list_buffers_entry, &cmd_list_buffers_entry,
@@ -111,8 +110,7 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
struct session *cmd_choose_session_list(struct sessionslist *); struct session *cmd_choose_session(struct sessions *);
struct session *cmd_choose_session(void);
struct client *cmd_choose_client(struct clients *); struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *); struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *); struct session *cmd_lookup_session(const char *, int *);
@@ -166,22 +164,6 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0); return (0);
} }
char **
cmd_copy_argv(int argc, char **argv)
{
char **new_argv;
int i;
if (argc == 0)
return (NULL);
new_argv = xcalloc(argc, sizeof *new_argv);
for (i = 0; i < argc; i++) {
if (argv[i] != NULL)
new_argv[i] = xstrdup(argv[i]);
}
return (new_argv);
}
void void
cmd_free_argv(int argc, char **argv) cmd_free_argv(int argc, char **argv)
{ {
@@ -316,9 +298,10 @@ cmd_current_session(struct cmd_ctx *ctx)
struct msg_command_data *data = ctx->msgdata; struct msg_command_data *data = ctx->msgdata;
struct client *c = ctx->cmdclient; struct client *c = ctx->cmdclient;
struct session *s; struct session *s;
struct sessionslist ss; struct sessions ss;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
u_int i;
int found; int found;
if (ctx->curclient != NULL && ctx->curclient->session != NULL) if (ctx->curclient != NULL && ctx->curclient->session != NULL)
@@ -331,7 +314,9 @@ cmd_current_session(struct cmd_ctx *ctx)
*/ */
if (c != NULL && c->tty.path != NULL) { if (c != NULL && c->tty.path != NULL) {
ARRAY_INIT(&ss); ARRAY_INIT(&ss);
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
found = 0; found = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
@@ -347,43 +332,29 @@ cmd_current_session(struct cmd_ctx *ctx)
ARRAY_ADD(&ss, s); ARRAY_ADD(&ss, s);
} }
s = cmd_choose_session_list(&ss); s = cmd_choose_session(&ss);
ARRAY_FREE(&ss); ARRAY_FREE(&ss);
if (s != NULL) if (s != NULL)
return (s); return (s);
} }
/* Use the session from the TMUX environment variable. */ /* Use the session from the TMUX environment variable. */
if (data != NULL && data->pid == getpid()) { if (data != NULL && data->pid != -1) {
s = session_find_by_index(data->idx); if (data->pid != getpid())
if (s != NULL) return (NULL);
return (s); if (data->idx > ARRAY_LENGTH(&sessions))
return (NULL);
if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
return (NULL);
return (s);
} }
return (cmd_choose_session()); return (cmd_choose_session(&sessions));
}
/* Find the most recently used session. */
struct session *
cmd_choose_session(void)
{
struct session *s, *sbest;
struct timeval *tv = NULL;
sbest = NULL;
RB_FOREACH(s, sessions, &sessions) {
if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
sbest = s;
tv = &s->activity_time;
}
}
return (sbest);
} }
/* Find the most recently used session from a list. */ /* Find the most recently used session from a list. */
struct session * struct session *
cmd_choose_session_list(struct sessionslist *ss) cmd_choose_session(struct sessions *ss)
{ {
struct session *s, *sbest; struct session *s, *sbest;
struct timeval *tv = NULL; struct timeval *tv = NULL;
@@ -531,6 +502,7 @@ struct session *
cmd_lookup_session(const char *name, int *ambiguous) cmd_lookup_session(const char *name, int *ambiguous)
{ {
struct session *s, *sfound; struct session *s, *sfound;
u_int i;
*ambiguous = 0; *ambiguous = 0;
@@ -539,15 +511,21 @@ cmd_lookup_session(const char *name, int *ambiguous)
* be unique so an exact match can't be ambigious and can just be * be unique so an exact match can't be ambigious and can just be
* returned. * returned.
*/ */
if ((s = session_find(name)) != NULL) for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
return (s); if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (strcmp(name, s->name) == 0)
return (s);
}
/* /*
* Otherwise look for partial matches, returning early if it is found to * Otherwise look for partial matches, returning early if it is found to
* be ambiguous. * be ambiguous.
*/ */
sfound = NULL; sfound = NULL;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (strncmp(name, s->name, strlen(name)) == 0 || if (strncmp(name, s->name, strlen(name)) == 0 ||
fnmatch(name, s->name, 0) == 0) { fnmatch(name, s->name, 0) == 0) {
if (sfound != NULL) { if (sfound != NULL) {

View File

@@ -1,4 +1,4 @@
/* $Id: compat.h,v 1.31 2010-11-11 20:45:49 nicm Exp $ */ /* $Id: compat.h,v 1.25 2010-06-06 13:00:46 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -16,20 +16,6 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#ifndef COMPAT_H
#define COMPAT_H
#ifndef __GNUC__
#define __attribute__(a)
#endif
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef HAVE_U_INT #ifndef HAVE_U_INT
typedef uint8_t u_int8_t; typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t; typedef uint16_t u_int16_t;
@@ -63,6 +49,14 @@ typedef uint64_t u_int64_t;
#include "compat/bitstring.h" #include "compat/bitstring.h"
#endif #endif
#ifdef HAVE_GETOPT
#include <getopt.h>
#endif
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#ifdef HAVE_PATHS_H #ifdef HAVE_PATHS_H
#include <paths.h> #include <paths.h>
#endif #endif
@@ -85,16 +79,10 @@ typedef uint64_t u_int64_t;
#include "compat/vis.h" #include "compat/vis.h"
#endif #endif
#ifdef HAVE_IMSG #ifndef HAVE_IMSG
#include <imsg.h>
#else
#include "compat/imsg.h" #include "compat/imsg.h"
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else #else
#include <inttypes.h> #include <imsg.h>
#endif #endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR #ifdef HAVE_BROKEN_CMSG_FIRSTHDR
@@ -135,6 +123,13 @@ typedef uint64_t u_int64_t;
#define SUN_LEN(sun) (sizeof (sun)->sun_path) #define SUN_LEN(sun) (sizeof (sun)->sun_path)
#endif #endif
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef timercmp #ifndef timercmp
#define timercmp(tvp, uvp, cmp) \ #define timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
@@ -159,18 +154,9 @@ typedef uint64_t u_int64_t;
#endif #endif
#ifndef HAVE_BZERO #ifndef HAVE_BZERO
#undef bzero
#define bzero(buf, len) memset(buf, 0, len); #define bzero(buf, len) memset(buf, 0, len);
#endif #endif
#ifndef HAVE_CLOSEFROM
/* closefrom.c */
#define HAVE_FCNTL_H
#define HAVE_DIRENT_H
#define HAVE_SYSCONF
void closefrom(int);
#endif
#ifndef HAVE_STRCASESTR #ifndef HAVE_STRCASESTR
/* strcasestr.c */ /* strcasestr.c */
char *strcasestr(const char *, const char *); char *strcasestr(const char *, const char *);
@@ -203,7 +189,6 @@ int daemon(int, int);
#ifndef HAVE_FORKPTY #ifndef HAVE_FORKPTY
/* forkpty.c */ /* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *); pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif #endif
@@ -224,9 +209,7 @@ int setenv(const char *, const char *, int);
int unsetenv(const char *); int unsetenv(const char *);
#endif #endif
#ifdef HAVE_GETOPT #ifndef HAVE_GETOPT
#include <getopt.h>
#else
/* getopt.c */ /* getopt.c */
extern int BSDopterr; extern int BSDopterr;
extern int BSDoptind; extern int BSDoptind;
@@ -241,5 +224,3 @@ int BSDgetopt(int, char *const *, const char *);
#define optreset BSDoptreset #define optreset BSDoptreset
#define optarg BSDoptarg #define optarg BSDoptarg
#endif #endif
#endif /* COMPAT_H */

View File

@@ -1,111 +0,0 @@
/* $Id: closefrom.c,v 1.1 2010-10-27 20:21:01 nicm Exp $ */
/*
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "tmux.h"
#ifndef HAVE_CLOSEFROM
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#ifndef OPEN_MAX
# define OPEN_MAX 256
#endif
#if 0
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
#endif /* lint */
/*
* Close all file descriptors greater than or equal to lowfd.
*/
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#else
void
closefrom(int lowfd)
{
long fd, maxfd;
#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
} else
#endif
{
/*
* Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor
* and then drop the rlimit such that it is below the open fd.
*/
#ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX);
#else
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd);
}
}
#endif /* !HAVE_FCNTL_CLOSEM */
#endif /* HAVE_CLOSEFROM */

View File

@@ -32,6 +32,10 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include "tmux.h" #include "tmux.h"
int int

View File

@@ -1,4 +1,4 @@
/* $Id: imsg.c,v 1.7 2010-11-13 16:29:05 nicm Exp $ */ /* $Id: imsg.c,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */ /* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
/* /*
@@ -111,7 +111,7 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
return (0); return (0);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
if ((imsg->data = malloc(datalen)) == NULL && datalen != 0) if ((imsg->data = malloc(datalen)) == NULL)
return (-1); return (-1);
if (imsg->hdr.flags & IMSGF_HASFD) if (imsg->hdr.flags & IMSGF_HASFD)

40
configure vendored
View File

@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# $Id: configure,v 1.59 2010-12-08 19:55:31 nicm Exp $ # $Id: configure,v 1.53 2010-06-06 13:00:47 tcunha Exp $
# #
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> # Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
# #
@@ -33,22 +33,18 @@ cat <<EOF >>$CONFIG_H
#undef HAVE_BROKEN_KQUEUE #undef HAVE_BROKEN_KQUEUE
#undef HAVE_BROKEN_POLL #undef HAVE_BROKEN_POLL
#undef HAVE_BZERO #undef HAVE_BZERO
#undef HAVE_CLOSEFROM #undef HAVE_CRYPT_H
#undef HAVE_DAEMON #undef HAVE_DAEMON
#undef HAVE_DIRFD
#undef HAVE_FCNTL_CLOSEM
#undef HAVE_FGETLN #undef HAVE_FGETLN
#undef HAVE_FORKPTY #undef HAVE_FORKPTY
#undef HAVE_GETOPT #undef HAVE_GETOPT
#undef HAVE_IMSG #undef HAVE_IMSG
#undef HAVE_LIBUTIL_H #undef HAVE_LIBUTIL_H
#undef HAVE_PATHS_H #undef HAVE_PATHS_H
#undef HAVE_PROC_PID
#undef HAVE_PROGNAME #undef HAVE_PROGNAME
#undef HAVE_PTY_H #undef HAVE_PTY_H
#undef HAVE_QUEUE_H #undef HAVE_QUEUE_H
#undef HAVE_SETPROCTITLE #undef HAVE_SETPROCTITLE
#undef HAVE_STDINT_H
#undef HAVE_STRCASESTR #undef HAVE_STRCASESTR
#undef HAVE_STRLCAT #undef HAVE_STRLCAT
#undef HAVE_STRLCPY #undef HAVE_STRLCPY
@@ -67,7 +63,6 @@ case $TMUX_PLATFORM in
#define HAVE_ASPRINTF #define HAVE_ASPRINTF
#define HAVE_BITSTRING_H #define HAVE_BITSTRING_H
#define HAVE_BZERO #define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON #define HAVE_DAEMON
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
@@ -78,7 +73,6 @@ case $TMUX_PLATFORM in
#define HAVE_QUEUE_H #define HAVE_QUEUE_H
#define HAVE_SETENV #define HAVE_SETENV
#define HAVE_SETPROCTITLE #define HAVE_SETPROCTITLE
#define HAVE_STDINT_H
#define HAVE_STRCASESTR #define HAVE_STRCASESTR
#define HAVE_STRLCAT #define HAVE_STRLCAT
#define HAVE_STRLCPY #define HAVE_STRLCPY
@@ -100,28 +94,24 @@ EOF
#define HAVE_ASPRINTF #define HAVE_ASPRINTF
#define HAVE_BZERO #define HAVE_BZERO
#define HAVE_DAEMON #define HAVE_DAEMON
#define HAVE_DIRFD
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_PROC_PID
#define HAVE_PROGNAME #define HAVE_PROGNAME
#define HAVE_PTY_H #define HAVE_PTY_H
#define HAVE_SETENV #define HAVE_SETENV
#define HAVE_STDINT_H
#define HAVE_STRCASESTR #define HAVE_STRCASESTR
#define HAVE_STRSEP #define HAVE_STRSEP
#define HAVE_U_INT #define HAVE_U_INT
EOF EOF
cat <<EOF >>$CONFIG_MK cat <<EOF >>$CONFIG_MK
CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE
LIBS+= -lncurses -lutil -levent -lrt LIBS+= -lncurses -lcrypt -lutil -levent -lrt
SRCS+= osdep-linux.c \ SRCS+= osdep-linux.c \
compat/closefrom.c \
compat/fgetln.c \ compat/fgetln.c \
compat/strlcat.c \ compat/strlcat.c \
compat/strlcpy.c \ compat/strlcpy.c \
compat/strtonum.c \ compat/strtonum.c \
compat/getopt.c \ compat/getopt.c \
compat/vis.c \ compat/vis.c \
compat/unvis.c \ compat/unvis.c \
compat/imsg-buffer.c \ compat/imsg-buffer.c \
@@ -131,14 +121,14 @@ EOF
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
AIX) AIX)
cat <<EOF >>$CONFIG_H cat <<EOF >>$CONFIG_H
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_SETENV #define HAVE_SETENV
#define HAVE_STDINT_H
EOF EOF
cat <<EOF >>$CONFIG_MK cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -levent LIBS+= -lcurses -levent
SRCS+= osdep-unknown.c \ SRCS+= osdep-unknown.c \
compat/asprintf.c \ compat/asprintf.c \
compat/closefrom.c \
compat/daemon.c \ compat/daemon.c \
compat/forkpty-aix.c \ compat/forkpty-aix.c \
compat/strcasestr.c \ compat/strcasestr.c \
@@ -157,7 +147,7 @@ EOF
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
SunOS) SunOS)
cat <<EOF >>$CONFIG_H cat <<EOF >>$CONFIG_H
#define HAVE_CLOSEFROM #define HAVE_CRYPT_H
#define HAVE_STRLCAT #define HAVE_STRLCAT
#define HAVE_STRLCPY #define HAVE_STRLCPY
EOF EOF
@@ -189,15 +179,12 @@ EOF
#define HAVE_BROKEN_POLL #define HAVE_BROKEN_POLL
#define HAVE_BZERO #define HAVE_BZERO
#define HAVE_DAEMON #define HAVE_DAEMON
#define HAVE_DIRFD
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_GETOPT #define HAVE_GETOPT
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_PROC_PID
#define HAVE_PROGNAME #define HAVE_PROGNAME
#define HAVE_SETENV #define HAVE_SETENV
#define HAVE_STDINT_H
#define HAVE_STRCASESTR #define HAVE_STRCASESTR
#define HAVE_STRLCAT #define HAVE_STRLCAT
#define HAVE_STRLCPY #define HAVE_STRLCPY
@@ -210,7 +197,6 @@ CPPFLAGS+= -I/opt/local/include
LDFLAGS+= -L/opt/local/lib LDFLAGS+= -L/opt/local/lib
LIBS+= -lcurses -levent LIBS+= -lcurses -levent
SRCS+= osdep-darwin.c \ SRCS+= osdep-darwin.c \
compat/closefrom.c \
compat/strtonum.c \ compat/strtonum.c \
compat/vis.c \ compat/vis.c \
compat/unvis.c \ compat/unvis.c \
@@ -224,7 +210,6 @@ EOF
#define HAVE_ASPRINTF #define HAVE_ASPRINTF
#define HAVE_BROKEN_KQUEUE #define HAVE_BROKEN_KQUEUE
#define HAVE_BZERO #define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON #define HAVE_DAEMON
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
@@ -234,16 +219,15 @@ EOF
#define HAVE_PROGNAME #define HAVE_PROGNAME
#define HAVE_SETENV #define HAVE_SETENV
#define HAVE_SETPROCTITLE #define HAVE_SETPROCTITLE
#define HAVE_STDINT_H
#define HAVE_STRCASESTR #define HAVE_STRCASESTR
#define HAVE_STRLCAT #define HAVE_STRLCAT
#define HAVE_STRLCPY #define HAVE_STRLCPY
#define HAVE_STRSEP
#define HAVE_STRTONUM #define HAVE_STRTONUM
#define HAVE_STRSEP
#define HAVE_U_INT #define HAVE_U_INT
EOF EOF
cat <<EOF >>$CONFIG_MK cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -lutil -levent LIBS+= -lcurses -lcrypt -lutil -levent
SRCS+= osdep-freebsd.c \ SRCS+= osdep-freebsd.c \
compat/vis.c \ compat/vis.c \
compat/unvis.c \ compat/unvis.c \
@@ -256,16 +240,14 @@ EOF
cat <<EOF >>$CONFIG_H cat <<EOF >>$CONFIG_H
#define HAVE_ASPRINTF #define HAVE_ASPRINTF
#define HAVE_BZERO #define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON #define HAVE_DAEMON
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_GETOPT #define HAVE_GETOPT
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_PROGNAME #define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_SETPROCTITLE #define HAVE_SETPROCTITLE
#define HAVE_STDINT_H #define HAVE_SETENV
#define HAVE_STRCASESTR #define HAVE_STRCASESTR
#define HAVE_STRLCAT #define HAVE_STRLCAT
#define HAVE_STRLCPY #define HAVE_STRLCPY
@@ -289,7 +271,7 @@ EOF
EOF EOF
fi fi
cat <<EOF >>$CONFIG_MK cat <<EOF >>$CONFIG_MK
LIBS+= -lutil -levent LIBS+= -lcrypt -lutil -levent
SRCS+= osdep-netbsd.c \ SRCS+= osdep-netbsd.c \
compat/strtonum.c \ compat/strtonum.c \
compat/vis.c \ compat/vis.c \

View File

@@ -1,105 +0,0 @@
# START tmux completion
# This file is in the public domain
# See: http://www.debian-administration.org/articles/317 for how to write more.
# Usage: Put "source bash_completion_tmux.sh" into your .bashrc
_tmux()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=" \
attach-session \
bind-key \
break-pane \
capture-pane \
choose-client \
choose-session \
choose-window \
clear-history \
clock-mode \
command-prompt \
confirm-before \
copy-buffer \
copy-mode \
delete-buffer \
detach-client \
display-message \
display-panes \
down-pane \
find-window \
has-session \
if-shell \
join-pane \
kill-pane \
kill-server \
kill-session \
kill-window \
last-window \
link-window \
list-buffers \
list-clients \
list-commands \
list-keys \
list-panes \
list-sessions \
list-windows \
load-buffer \
lock-client \
lock-server \
lock-session \
move-window \
new-session \
new-window \
next-layout \
next-window \
paste-buffer \
pipe-pane \
previous-layout \
previous-window \
refresh-client \
rename-session \
rename-window \
resize-pane \
respawn-window \
rotate-window \
run-shell \
save-buffer \
select-layout \
select-pane \
select-prompt \
select-window \
send-keys \
send-prefix \
server-info \
set-buffer \
set-environment \
set-option \
set-window-option \
show-buffer \
show-environment \
show-messages \
show-options \
show-window-options \
source-file \
split-window \
start-server \
suspend-client \
swap-pane \
swap-window \
switch-client \
unbind-key \
unlink-window \
up-pane"
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
return 0
}
complete -F _tmux tmux
# END tmux completion

View File

@@ -1,4 +1,4 @@
# $Id: screen-keys.conf,v 1.7 2010-07-31 11:39:13 nicm Exp $ # $Id: screen-keys.conf,v 1.6 2010-02-02 21:34:16 nicm Exp $
# #
# By Nicholas Marriott. Public domain. # By Nicholas Marriott. Public domain.
# #
@@ -93,9 +93,9 @@ bind | split-window
# :kB: focus up # :kB: focus up
unbind Tab unbind Tab
bind Tab select-pane -t:.+ bind Tab down-pane
unbind BTab unbind BTab
bind BTab select-pane -t:.- bind BTab up-pane
# " windowlist -b # " windowlist -b
unbind '"' unbind '"'

View File

@@ -1,7 +1,7 @@
" Vim syntax file " Vim syntax file
" Language: tmux(1) configuration file " Language: tmux(1) configuration file
" Maintainer: Tiago Cunha <me@tiagocunha.org> " Maintainer: Tiago Cunha <me@tiagocunha.org>
" Last Change: $Date: 2010-07-27 18:29:07 $ " Last Change: $Date: 2010-07-02 02:46:39 $
" License: This file is placed in the public domain. " License: This file is placed in the public domain.
if version < 600 if version < 600
@@ -31,9 +31,9 @@ syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb
syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands
syn keyword tmuxCmds movew move-window respawnw respawn-window syn keyword tmuxCmds movew move-window respawnw respawn-window
syn keyword tmuxCmds source[-file] info server-info clock-mode lock[-server] syn keyword tmuxCmds source[-file] info server-info clock-mode lock[-server]
syn keyword tmuxCmds saveb save-buffer killp syn keyword tmuxCmds saveb save-buffer downp down-pane killp
syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp
syn keyword tmuxCmds swap-pane splitw split-window choose-session syn keyword tmuxCmds swap-pane splitw split-window upp up-pane choose-session
syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc
syn keyword tmuxCmds suspend-client findw find-window breakp break-pane nextl syn keyword tmuxCmds suspend-client findw find-window breakp break-pane nextl
syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before] syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before]
@@ -72,8 +72,7 @@ syn keyword tmuxOptsSetw main-pane-width main-pane-height monitor-content
syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg
syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes
syn keyword tmuxOptsSetw window-status-format window-status-current-format syn keyword tmuxOptsSetw window-status-format window-status-current-format
syn keyword tmuxOptsSetw word-separators window-status-alert-alert syn keyword tmuxOptsSetw word-separators
syn keyword tmuxOptsSetw window-status-alert-bg window-status-alert-fg
syn keyword tmuxTodo FIXME NOTE TODO XXX contained syn keyword tmuxTodo FIXME NOTE TODO XXX contained

View File

@@ -1,24 +1,23 @@
# $Id: vim-keys.conf,v 1.2 2010-09-18 09:36:15 nicm Exp $ # $Id: vim-keys.conf,v 1.1 2010-01-17 16:24:09 nicm Exp $
# #
# vim-keys.conf, v1.2 2010/09/12 # vim-keys.conf, v1.0 2010/01/15
# #
# By Daniel Thau. Public domain. # By Daniel Thau. Public domain.
# #
# This configuration file binds many vi- and vim-like bindings to the # This configuration file binds many vi- and vim-like bindings to the
# appropriate tmux key bindings. Note that for many key bindings there is no # appropriate tmux key bindings. Note that for many key bindings there is no
# tmux analogue. This is intended for tmux 1.3, which handles pane selection # tmux analogue.
# differently from the previous versions
# split windows like vim # split windows like vim
# vim's definition of a horizontal/vertical split is reversed from tmux's # vim's definition of a horizontal/vertical split is reversed from tmux's
bind s split-window -v bind s split-window -v
bind v split-window -h bind v split-window -h
# move around panes with hjkl, as one would in vim after pressing ctrl-w # move around panes with j and k, a bit like vim
bind h select-pane -L # as of tmux 1.1, there is no way to move based on pane position (ie, no way to
bind j select-pane -D # move the pane to the right)
bind k select-pane -U bind j down-pane
bind l select-pane -R bind k up-pane
# resize panes like vim # resize panes like vim
# feel free to change the "1" to however many lines you want to resize by, only # feel free to change the "1" to however many lines you want to resize by, only

View File

@@ -1,4 +1,4 @@
/* $Id: input-keys.c,v 1.45 2010-09-07 19:32:58 nicm Exp $ */ /* $Id: input-keys.c,v 1.44 2009-12-04 22:14:47 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

14
input.c
View File

@@ -1,4 +1,4 @@
/* $Id: input.c,v 1.111 2010-12-25 23:43:53 tcunha Exp $ */ /* $Id: input.c,v 1.109 2010-04-18 15:11:47 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -681,9 +681,7 @@ input_parse(struct window_pane *wp)
if (EVBUFFER_LENGTH(evb) == 0) if (EVBUFFER_LENGTH(evb) == 0)
return; return;
wp->window->flags |= WINDOW_ACTIVITY; wp->window->flags |= WINDOW_ACTIVITY;
wp->window->flags &= ~WINDOW_SILENCE;
/* /*
* Open the screen. Use NULL wp if there is a mode set as don't want to * Open the screen. Use NULL wp if there is a mode set as don't want to
@@ -720,11 +718,11 @@ input_parse(struct window_pane *wp)
* Execute the handler, if any. Don't switch state if it * Execute the handler, if any. Don't switch state if it
* returns non-zero. * returns non-zero.
*/ */
if (itr->handler != NULL && itr->handler(ictx) != 0) if (itr->handler && itr->handler(ictx) != 0)
continue; continue;
/* And switch state, if necessary. */ /* And switch state, if necessary. */
if (itr->state != NULL) { if (itr->state) {
if (ictx->state->exit != NULL) if (ictx->state->exit != NULL)
ictx->state->exit(ictx); ictx->state->exit(ictx);
ictx->state = itr->state; ictx->state = itr->state;
@@ -924,9 +922,9 @@ input_c0_dispatch(struct input_ctx *ictx)
int int
input_esc_dispatch(struct input_ctx *ictx) input_esc_dispatch(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s; struct screen *s = sctx->s;
struct input_table_entry *entry; struct input_table_entry *entry;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);

8
job.c
View File

@@ -1,4 +1,4 @@
/* $Id: job.c,v 1.19 2010-10-24 00:45:57 tcunha Exp $ */ /* $Id: job.c,v 1.17 2010-05-14 14:30:01 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -148,7 +148,7 @@ job_run(struct job *job)
case -1: case -1:
return (-1); return (-1);
case 0: /* child */ case 0: /* child */
clear_signals(1); clear_signals();
environ_push(&global_environ); environ_push(&global_environ);
@@ -168,8 +168,6 @@ job_run(struct job *job)
if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
close(nullfd); close(nullfd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
fatal("execl failed"); fatal("execl failed");
default: /* parent */ default: /* parent */
@@ -180,6 +178,8 @@ job_run(struct job *job)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
if (job->event != NULL) if (job->event != NULL)
bufferevent_free(job->event); bufferevent_free(job->event);

View File

@@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.97 2010-12-11 18:42:20 nicm Exp $ */ /* $Id: key-bindings.c,v 1.94 2010-07-02 02:43:01 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -108,8 +108,6 @@ key_bindings_init(void)
{ '#', 0, &cmd_list_buffers_entry }, { '#', 0, &cmd_list_buffers_entry },
{ '%', 0, &cmd_split_window_entry }, { '%', 0, &cmd_split_window_entry },
{ '&', 0, &cmd_confirm_before_entry }, { '&', 0, &cmd_confirm_before_entry },
{ '(', 0, &cmd_switch_client_entry },
{ ')', 0, &cmd_switch_client_entry },
{ ',', 0, &cmd_command_prompt_entry }, { ',', 0, &cmd_command_prompt_entry },
{ '-', 0, &cmd_delete_buffer_entry }, { '-', 0, &cmd_delete_buffer_entry },
{ '.', 0, &cmd_command_prompt_entry }, { '.', 0, &cmd_command_prompt_entry },
@@ -124,11 +122,9 @@ key_bindings_init(void)
{ '8', 0, &cmd_select_window_entry }, { '8', 0, &cmd_select_window_entry },
{ '9', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry },
{ ':', 0, &cmd_command_prompt_entry }, { ':', 0, &cmd_command_prompt_entry },
{ ';', 0, &cmd_last_pane_entry },
{ '=', 0, &cmd_choose_buffer_entry }, { '=', 0, &cmd_choose_buffer_entry },
{ '?', 0, &cmd_list_keys_entry }, { '?', 0, &cmd_list_keys_entry },
{ 'D', 0, &cmd_choose_client_entry }, { 'D', 0, &cmd_choose_client_entry },
{ 'L', 0, &cmd_switch_client_entry },
{ '[', 0, &cmd_copy_mode_entry }, { '[', 0, &cmd_copy_mode_entry },
{ '\'', 0, &cmd_command_prompt_entry }, { '\'', 0, &cmd_command_prompt_entry },
{ '\002', /* C-b */ 0, &cmd_send_prefix_entry }, { '\002', /* C-b */ 0, &cmd_send_prefix_entry },

View File

@@ -1,4 +1,4 @@
/* $Id: layout-set.c,v 1.8 2010-12-22 15:23:59 tcunha Exp $ */ /* $Id: layout-set.c,v 1.6 2010-05-14 14:16:37 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -135,9 +135,10 @@ layout_set_even_h(struct window *w)
return; return;
/* How many can we fit? */ /* How many can we fit? */
width = (w->sx - (n - 1)) / n; if (w->sx / n < PANE_MINIMUM + 1)
if (width < PANE_MINIMUM) width = PANE_MINIMUM + 1;
width = PANE_MINIMUM; else
width = w->sx / n;
/* Free the old root and construct a new. */ /* Free the old root and construct a new. */
layout_free(w); layout_free(w);
@@ -150,12 +151,12 @@ layout_set_even_h(struct window *w)
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */ /* Create child cell. */
lcnew = layout_create_cell(lc); lcnew = layout_create_cell(lc);
layout_set_size(lcnew, width, w->sy, xoff, 0); layout_set_size(lcnew, width - 1, w->sy, xoff, 0);
layout_make_leaf(lcnew, wp); layout_make_leaf(lcnew, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++; i++;
xoff += width + 1; xoff += width;
} }
/* Allocate any remaining space. */ /* Allocate any remaining space. */
@@ -188,9 +189,10 @@ layout_set_even_v(struct window *w)
return; return;
/* How many can we fit? */ /* How many can we fit? */
height = (w->sy - (n - 1)) / n; if (w->sy / n < PANE_MINIMUM + 1)
if (height < PANE_MINIMUM) height = PANE_MINIMUM + 1;
height = PANE_MINIMUM; else
height = w->sy / n;
/* Free the old root and construct a new. */ /* Free the old root and construct a new. */
layout_free(w); layout_free(w);
@@ -203,12 +205,12 @@ layout_set_even_v(struct window *w)
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */ /* Create child cell. */
lcnew = layout_create_cell(lc); lcnew = layout_create_cell(lc);
layout_set_size(lcnew, w->sx, height, 0, yoff); layout_set_size(lcnew, w->sx, height - 1, 0, yoff);
layout_make_leaf(lcnew, wp); layout_make_leaf(lcnew, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++; i++;
yoff += height + 1; yoff += height;
} }
/* Allocate any remaining space. */ /* Allocate any remaining space. */
@@ -231,8 +233,8 @@ layout_set_main_h(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcrow, *lcchild; struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
u_int n, mainheight, otherheight, width, height; u_int n, mainheight, width, height, used;
u_int used, i, j, columns, rows, totalrows; u_int i, j, columns, rows, totalrows;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -242,26 +244,16 @@ layout_set_main_h(struct window *w)
return; return;
n--; /* take off main pane */ n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */ /* How many rows and columns will be needed? */
columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */ columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */
if (columns == 0) if (columns == 0)
columns = 1; columns = 1;
rows = 1 + (n - 1) / columns; rows = 1 + (n - 1) / columns;
columns = 1 + (n - 1) / rows; columns = 1 + (n - 1) / rows;
width = (w->sx - (n - 1)) / columns; width = w->sx / columns;
/* Get the main pane height and add one for separator line. */ /* Get the main pane height and add one for separator line. */
mainheight = options_get_number(&w->options, "main-pane-height") + 1; mainheight = options_get_number(&w->options, "main-pane-height") + 1;
/* Get the optional other pane height and add one for separator line. */
otherheight = options_get_number(&w->options, "other-pane-height") + 1;
/*
* If an other pane height was specified, honour it so long as it
* doesn't shrink the main height to less than the main-pane-height
*/
if (otherheight > 1 && w->sx - otherheight > mainheight)
mainheight = w->sx - otherheight;
if (mainheight < PANE_MINIMUM + 1) if (mainheight < PANE_MINIMUM + 1)
mainheight = PANE_MINIMUM + 1; mainheight = PANE_MINIMUM + 1;
@@ -272,14 +264,14 @@ layout_set_main_h(struct window *w)
mainheight = PANE_MINIMUM + 2; mainheight = PANE_MINIMUM + 2;
else else
mainheight = w->sy - totalrows; mainheight = w->sy - totalrows;
height = PANE_MINIMUM; height = PANE_MINIMUM + 1;
} else } else
height = (w->sy - mainheight - (rows - 1)) / rows; height = (w->sy - mainheight) / rows;
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0); layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM); layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create the main pane. */ /* Create the main pane. */
@@ -297,7 +289,7 @@ layout_set_main_h(struct window *w)
/* Create the new row. */ /* Create the new row. */
lcrow = layout_create_cell(lc); lcrow = layout_create_cell(lc);
layout_set_size(lcrow, w->sx, height, 0, 0); layout_set_size(lcrow, w->sx, height - 1, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */ /* If only one column, just use the row directly. */
@@ -312,7 +304,7 @@ layout_set_main_h(struct window *w)
for (i = 0; i < columns; i++) { for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */ /* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow); lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width, height, 0, 0); layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp); layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
@@ -324,7 +316,7 @@ layout_set_main_h(struct window *w)
/* Adjust the row to fit the full width if necessary. */ /* Adjust the row to fit the full width if necessary. */
if (i == columns) if (i == columns)
i--; i--;
used = ((i + 1) * (width + 1)) - 1; used = ((i + 1) * width) - 1;
if (w->sx <= used) if (w->sx <= used)
continue; continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
@@ -332,7 +324,7 @@ layout_set_main_h(struct window *w)
} }
/* Adjust the last row height to fit if necessary. */ /* Adjust the last row height to fit if necessary. */
used = mainheight + (rows * height) + rows - 1; used = mainheight + (rows * height) - 1;
if (w->sy > used) { if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells); lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
@@ -352,8 +344,8 @@ layout_set_main_v(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lccolumn, *lcchild; struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
u_int n, mainwidth, otherwidth, width, height; u_int n, mainwidth, width, height, used;
u_int used, i, j, columns, rows, totalcolumns; u_int i, j, columns, rows, totalcolumns;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -363,26 +355,16 @@ layout_set_main_v(struct window *w)
return; return;
n--; /* take off main pane */ n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */ /* How many rows and columns will be needed? */
rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */ rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */
if (rows == 0) if (rows == 0)
rows = 1; rows = 1;
columns = 1 + (n - 1) / rows; columns = 1 + (n - 1) / rows;
rows = 1 + (n - 1) / columns; rows = 1 + (n - 1) / columns;
height = (w->sy - (n - 1)) / rows; height = w->sy / rows;
/* Get the main pane width and add one for separator line. */ /* Get the main pane width and add one for separator line. */
mainwidth = options_get_number(&w->options, "main-pane-width") + 1; mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
/* Get the optional other pane width and add one for separator line. */
otherwidth = options_get_number(&w->options, "other-pane-width") + 1;
/*
* If an other pane width was specified, honour it so long as it
* doesn't shrink the main width to less than the main-pane-width
*/
if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
mainwidth = w->sx - otherwidth;
if (mainwidth < PANE_MINIMUM + 1) if (mainwidth < PANE_MINIMUM + 1)
mainwidth = PANE_MINIMUM + 1; mainwidth = PANE_MINIMUM + 1;
@@ -393,14 +375,14 @@ layout_set_main_v(struct window *w)
mainwidth = PANE_MINIMUM + 2; mainwidth = PANE_MINIMUM + 2;
else else
mainwidth = w->sx - totalcolumns; mainwidth = w->sx - totalcolumns;
width = PANE_MINIMUM; width = PANE_MINIMUM + 1;
} else } else
width = (w->sx - mainwidth - (columns - 1)) / columns; width = (w->sx - mainwidth) / columns;
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0); layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT); layout_make_node(lc, LAYOUT_LEFTRIGHT);
/* Create the main pane. */ /* Create the main pane. */
@@ -418,7 +400,7 @@ layout_set_main_v(struct window *w)
/* Create the new column. */ /* Create the new column. */
lccolumn = layout_create_cell(lc); lccolumn = layout_create_cell(lc);
layout_set_size(lccolumn, width, w->sy, 0, 0); layout_set_size(lccolumn, width - 1, w->sy, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry); TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
/* If only one row, just use the row directly. */ /* If only one row, just use the row directly. */
@@ -433,7 +415,7 @@ layout_set_main_v(struct window *w)
for (i = 0; i < rows; i++) { for (i = 0; i < rows; i++) {
/* Create and add a pane cell. */ /* Create and add a pane cell. */
lcchild = layout_create_cell(lccolumn); lcchild = layout_create_cell(lccolumn);
layout_set_size(lcchild, width, height, 0, 0); layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp); layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry); TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
@@ -445,7 +427,7 @@ layout_set_main_v(struct window *w)
/* Adjust the column to fit the full height if necessary. */ /* Adjust the column to fit the full height if necessary. */
if (i == rows) if (i == rows)
i--; i--;
used = ((i + 1) * (height + 1)) - 1; used = ((i + 1) * height) - 1;
if (w->sy <= used) if (w->sy <= used)
continue; continue;
lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
@@ -453,7 +435,7 @@ layout_set_main_v(struct window *w)
} }
/* Adjust the last column width to fit if necessary. */ /* Adjust the last column width to fit if necessary. */
used = mainwidth + (columns * width) + columns - 1; used = mainwidth + (columns * width) - 1;
if (w->sx > used) { if (w->sx > used) {
lccolumn = TAILQ_LAST(&lc->cells, layout_cells); lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used); layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
@@ -492,18 +474,17 @@ layout_set_tiled(struct window *w)
} }
/* What width and height should they be? */ /* What width and height should they be? */
width = (w->sx - (columns - 1)) / columns; width = w->sx / columns;
if (width < PANE_MINIMUM) if (width < PANE_MINIMUM + 1)
width = PANE_MINIMUM; width = PANE_MINIMUM + 1;
height = (w->sy - (rows - 1)) / rows; height = w->sy / rows;
if (height < PANE_MINIMUM) if (width < PANE_MINIMUM + 1)
height = PANE_MINIMUM; width = PANE_MINIMUM + 1;
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, (width + 1) * columns - 1, layout_set_size(lc, width * columns, height * rows, 0, 0);
(height + 1) * rows - 1, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM); layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create a grid of the cells. */ /* Create a grid of the cells. */
@@ -515,7 +496,7 @@ layout_set_tiled(struct window *w)
/* Create the new row. */ /* Create the new row. */
lcrow = layout_create_cell(lc); lcrow = layout_create_cell(lc);
layout_set_size(lcrow, w->sx, height, 0, 0); layout_set_size(lcrow, w->sx, height - 1, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */ /* If only one column, just use the row directly. */
@@ -530,7 +511,7 @@ layout_set_tiled(struct window *w)
for (i = 0; i < columns; i++) { for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */ /* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow); lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width, height, 0, 0); layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp); layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
@@ -545,7 +526,7 @@ layout_set_tiled(struct window *w)
*/ */
if (i == columns) if (i == columns)
i--; i--;
used = ((i + 1) * (width + 1)) - 1; used = ((i + 1) * width) - 1;
if (w->sx <= used) if (w->sx <= used)
continue; continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
@@ -553,7 +534,7 @@ layout_set_tiled(struct window *w)
} }
/* Adjust the last row height to fit if necessary. */ /* Adjust the last row height to fit if necessary. */
used = (rows * height) + rows - 1; used = (rows * height) - 1;
if (w->sy > used) { if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells); lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);

View File

@@ -1,4 +1,4 @@
/* $Id: resize.c,v 1.27 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: resize.c,v 1.25 2010-06-22 23:26:18 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -52,7 +52,11 @@ recalculate_sizes(void)
u_int i, j, ssx, ssy, has, limit; u_int i, j, ssx, ssy, has, limit;
int flag; int flag;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) { for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j); c = ARRAY_ITEM(&clients, j);
@@ -94,8 +98,9 @@ recalculate_sizes(void)
flag = options_get_number(&w->options, "aggressive-resize"); flag = options_get_number(&w->options, "aggressive-resize");
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
RB_FOREACH(s, sessions, &sessions) { for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
if (s->flags & SESSION_UNATTACHED) s = ARRAY_ITEM(&sessions, j);
if (s == NULL || s->flags & SESSION_UNATTACHED)
continue; continue;
if (flag) if (flag)
has = s->curw->window == w; has = s->curw->window == w;
@@ -108,8 +113,11 @@ recalculate_sizes(void)
ssy = s->sy; ssy = s->sy;
} }
} }
if (ssx == UINT_MAX || ssy == UINT_MAX) if (ssx == UINT_MAX || ssy == UINT_MAX) {
w->flags |= WINDOW_HIDDEN;
continue; continue;
}
w->flags &= ~WINDOW_HIDDEN;
limit = options_get_number(&w->options, "force-width"); limit = options_get_number(&w->options, "force-width");
if (limit != 0 && ssx > limit) if (limit != 0 && ssx > limit)

View File

@@ -1,4 +1,4 @@
/* $Id: screen-redraw.c,v 1.53 2010-09-18 15:43:53 tcunha Exp $ */ /* $Id: screen-redraw.c,v 1.52 2010-02-05 01:31:06 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -41,8 +41,6 @@ void screen_redraw_draw_number(struct client *, struct window_pane *);
#define CELL_JOIN 11 #define CELL_JOIN 11
#define CELL_OUTSIDE 12 #define CELL_OUTSIDE 12
#define CELL_BORDERS " xqlkmjwvtun~"
/* Check if cell is on the border of a particular pane. */ /* Check if cell is on the border of a particular pane. */
int int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py) screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@@ -175,6 +173,8 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
struct grid_cell active_gc, other_gc; struct grid_cell active_gc, other_gc;
u_int i, j, type; u_int i, j, type;
int status, fg, bg; int status, fg, bg;
const u_char *base, *ptr;
u_char ch, border[20];
/* Get status line, er, status. */ /* Get status line, er, status. */
if (c->message_string != NULL || c->prompt_string != NULL) if (c->message_string != NULL || c->prompt_string != NULL)
@@ -193,7 +193,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
memcpy(&other_gc, &grid_default_cell, sizeof other_gc); memcpy(&other_gc, &grid_default_cell, sizeof other_gc);
memcpy(&active_gc, &grid_default_cell, sizeof active_gc); memcpy(&active_gc, &grid_default_cell, sizeof active_gc);
active_gc.data = other_gc.data = 'x'; /* not space */ active_gc.data = other_gc.data = 'x'; /* not space */
active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
fg = options_get_number(&c->session->options, "pane-border-fg"); fg = options_get_number(&c->session->options, "pane-border-fg");
colour_set_fg(&other_gc, fg); colour_set_fg(&other_gc, fg);
bg = options_get_number(&c->session->options, "pane-border-bg"); bg = options_get_number(&c->session->options, "pane-border-bg");
@@ -204,6 +203,16 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
colour_set_bg(&active_gc, bg); colour_set_bg(&active_gc, bg);
/* Draw background and borders. */ /* Draw background and borders. */
strlcpy(border, " |-....--||+.", sizeof border);
if (tty_term_has(tty->term, TTYC_ACSC)) {
base = " xqlkmjwvtun~";
for (ptr = base; *ptr != '\0'; ptr++) {
if ((ch = tty_get_acs(tty, *ptr)) != '\0')
border[ptr - base] = ch;
}
other_gc.attr |= GRID_ATTR_CHARSET;
active_gc.attr |= GRID_ATTR_CHARSET;
}
for (j = 0; j < tty->sy - status; j++) { for (j = 0; j < tty->sy - status; j++) {
if (status_only && j != tty->sy - 1) if (status_only && j != tty->sy - 1)
continue; continue;
@@ -216,7 +225,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
else else
tty_attributes(tty, &other_gc); tty_attributes(tty, &other_gc);
tty_cursor(tty, i, j); tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]); tty_putc(tty, border[type]);
} }
} }

View File

@@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.103 2010-12-11 17:57:28 nicm Exp $ */ /* $Id: screen.c,v 1.101 2010-04-06 22:01:32 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <netdb.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -287,7 +286,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
*/ */
if (sel->ex < sel->sx) { if (sel->ex < sel->sx) {
/* Cursor (ex) is on the left. */ /* Cursor (ex) is on the left. */
if (px < sel->ex) if (px <= sel->ex)
return (0); return (0);
if (px > sel->sx) if (px > sel->sx)
@@ -297,7 +296,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
if (px < sel->sx) if (px < sel->sx)
return (0); return (0);
if (px > sel->ex) if (px >= sel->ex)
return (0); return (0);
} }
} else { } else {

View File

@@ -1,4 +1,4 @@
/* $Id: server-client.c,v 1.48 2010-12-22 15:31:00 tcunha Exp $ */ /* $Id: server-client.c,v 1.35 2010-07-17 14:36:40 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,14 +28,9 @@
void server_client_handle_key(int, struct mouse_event *, void *); void server_client_handle_key(int, struct mouse_event *, void *);
void server_client_repeat_timer(int, short, void *); void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *);
void server_client_check_backoff(struct client *);
void server_client_check_redraw(struct client *); void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *); void server_client_set_title(struct client *);
void server_client_reset_state(struct client *); void server_client_reset_state(struct client *);
void server_client_in_callback(struct bufferevent *, short, void *);
void server_client_out_callback(struct bufferevent *, short, void *);
void server_client_err_callback(struct bufferevent *, short, void *);
int server_client_msg_dispatch(struct client *); int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *); void server_client_msg_command(struct client *, struct msg_command_data *);
@@ -59,6 +54,8 @@ server_client_create(int fd)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
c = xcalloc(1, sizeof *c); c = xcalloc(1, sizeof *c);
c->references = 0; c->references = 0;
@@ -69,15 +66,16 @@ server_client_create(int fd)
fatal("gettimeofday failed"); fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
c->stdin_event = NULL; ARRAY_INIT(&c->prompt_hdata);
c->stdout_event = NULL;
c->stderr_event = NULL; c->stdin_file = NULL;
c->stdout_file = NULL;
c->stderr_file = NULL;
c->tty.fd = -1; c->tty.fd = -1;
c->title = NULL; c->title = NULL;
c->session = NULL; c->session = NULL;
c->last_session = NULL;
c->tty.sx = 80; c->tty.sx = 80;
c->tty.sy = 24; c->tty.sy = 24;
@@ -123,18 +121,12 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL) if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty); tty_free(&c->tty);
if (c->stdin_fd != -1) if (c->stdin_file != NULL)
close(c->stdin_fd); fclose(c->stdin_file);
if (c->stdin_event != NULL) if (c->stdout_file != NULL)
bufferevent_free(c->stdin_event); fclose(c->stdout_file);
if (c->stdout_fd != -1) if (c->stderr_file != NULL)
close(c->stdout_fd); fclose(c->stderr_file);
if (c->stdout_event != NULL)
bufferevent_free(c->stdout_event);
if (c->stderr_fd != -1)
close(c->stderr_fd);
if (c->stderr_event != NULL)
bufferevent_free(c->stderr_event);
screen_free(&c->status); screen_free(&c->status);
job_tree_free(&c->status_jobs); job_tree_free(&c->status_jobs);
@@ -159,6 +151,9 @@ server_client_lost(struct client *c)
xfree(c->prompt_string); xfree(c->prompt_string);
if (c->prompt_buffer != NULL) if (c->prompt_buffer != NULL)
xfree(c->prompt_buffer); xfree(c->prompt_buffer);
for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
xfree(ARRAY_ITEM(&c->prompt_hdata, i));
ARRAY_FREE(&c->prompt_hdata);
if (c->cwd != NULL) if (c->cwd != NULL)
xfree(c->cwd); xfree(c->cwd);
@@ -178,7 +173,6 @@ server_client_lost(struct client *c)
c->flags |= CLIENT_DEAD; c->flags |= CLIENT_DEAD;
recalculate_sizes(); recalculate_sizes();
server_check_unattached();
server_update_socket(); server_update_socket();
} }
@@ -395,14 +389,11 @@ server_client_loop(void)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL) if (c == NULL || c->session == NULL)
continue; continue;
server_client_check_exit(c); server_client_check_redraw(c);
if (c->session != NULL) { server_client_reset_state(c);
server_client_check_redraw(c);
server_client_reset_state(c);
}
} }
/* /*
@@ -465,72 +456,6 @@ server_client_repeat_timer(unused int fd, unused short events, void *data)
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
} }
/* Check if client should be exited. */
void
server_client_check_exit(struct client *c)
{
struct msg_exit_data exitdata;
if (!(c->flags & CLIENT_EXIT))
return;
if (c->stdout_fd != -1 && c->stdout_event != NULL &&
EVBUFFER_LENGTH(c->stdout_event->output) != 0)
return;
if (c->stderr_fd != -1 && c->stderr_event != NULL &&
EVBUFFER_LENGTH(c->stderr_event->output) != 0)
return;
exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
c->flags &= ~CLIENT_EXIT;
}
/*
* Check if the client should backoff. During backoff, data from external
* programs is not written to the terminal. When the existing data drains, the
* client is redrawn.
*
* There are two backoff phases - both the tty and client have backoff flags -
* the first to allow existing data to drain and the latter to ensure backoff
* is disabled until the redraw has finished and prevent the redraw triggering
* another backoff.
*/
void
server_client_check_backoff(struct client *c)
{
struct tty *tty = &c->tty;
size_t used;
used = EVBUFFER_LENGTH(tty->event->output);
/*
* If in the second backoff phase (redrawing), don't check backoff
* until the redraw has completed (or enough of it to drop below the
* backoff threshold).
*/
if (c->flags & CLIENT_BACKOFF) {
if (used > BACKOFF_THRESHOLD)
return;
c->flags &= ~CLIENT_BACKOFF;
return;
}
/* Once drained, allow data through again and schedule redraw. */
if (tty->flags & TTY_BACKOFF) {
if (used != 0)
return;
tty->flags &= ~TTY_BACKOFF;
c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
return;
}
/* If too much data, start backoff. */
if (used > BACKOFF_THRESHOLD)
tty->flags |= TTY_BACKOFF;
}
/* Check for client redraws. */ /* Check for client redraws. */
void void
server_client_check_redraw(struct client *c) server_client_check_redraw(struct client *c)
@@ -559,10 +484,6 @@ server_client_check_redraw(struct client *c)
if (c->flags & CLIENT_REDRAW) { if (c->flags & CLIENT_REDRAW) {
screen_redraw_screen(c, 0, 0); screen_redraw_screen(c, 0, 0);
c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
} else if (c->flags & CLIENT_REDRAWWINDOW) {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
screen_redraw_pane(c, wp);
c->flags &= ~CLIENT_REDRAWWINDOW;
} else { } else {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
if (wp->flags & PANE_REDRAW) if (wp->flags & PANE_REDRAW)
@@ -601,52 +522,6 @@ server_client_set_title(struct client *c)
xfree(title); xfree(title);
} }
/*
* Error callback for client stdin. Caller must increase reference count when
* enabling event!
*/
void
server_client_in_callback(
unused struct bufferevent *bufev, unused short what, void *data)
{
struct client *c = data;
c->references--;
if (c->flags & CLIENT_DEAD)
return;
bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE);
close(c->stdin_fd);
c->stdin_fd = -1;
if (c->stdin_callback != NULL)
c->stdin_callback(c, c->stdin_data);
}
/* Error callback for client stdout. */
void
server_client_out_callback(
unused struct bufferevent *bufev, unused short what, unused void *data)
{
struct client *c = data;
bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE);
close(c->stdout_fd);
c->stdout_fd = -1;
}
/* Error callback for client stderr. */
void
server_client_err_callback(
unused struct bufferevent *bufev, unused short what, unused void *data)
{
struct client *c = data;
bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE);
close(c->stderr_fd);
c->stderr_fd = -1;
}
/* Dispatch message from client. */ /* Dispatch message from client. */
int int
server_client_msg_dispatch(struct client *c) server_client_msg_dispatch(struct client *c)
@@ -656,7 +531,6 @@ server_client_msg_dispatch(struct client *c)
struct msg_identify_data identifydata; struct msg_identify_data identifydata;
struct msg_environ_data environdata; struct msg_environ_data environdata;
ssize_t n, datalen; ssize_t n, datalen;
int mode;
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
return (-1); return (-1);
@@ -691,15 +565,9 @@ server_client_msg_dispatch(struct client *c)
fatalx("MSG_IDENTIFY missing fd"); fatalx("MSG_IDENTIFY missing fd");
memcpy(&identifydata, imsg.data, sizeof identifydata); memcpy(&identifydata, imsg.data, sizeof identifydata);
c->stdin_fd = imsg.fd; c->stdin_file = fdopen(imsg.fd, "r");
c->stdin_event = bufferevent_new(c->stdin_fd, if (c->stdin_file == NULL)
NULL, NULL, server_client_in_callback, c); fatal("fdopen(stdin) failed");
if (c->stdin_event == NULL)
fatalx("failed to create stdin event");
if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1)
fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK);
server_client_msg_identify(c, &identifydata, imsg.fd); server_client_msg_identify(c, &identifydata, imsg.fd);
break; break;
case MSG_STDOUT: case MSG_STDOUT:
@@ -708,14 +576,9 @@ server_client_msg_dispatch(struct client *c)
if (imsg.fd == -1) if (imsg.fd == -1)
fatalx("MSG_STDOUT missing fd"); fatalx("MSG_STDOUT missing fd");
c->stdout_fd = imsg.fd; c->stdout_file = fdopen(imsg.fd, "w");
c->stdout_event = bufferevent_new(c->stdout_fd, if (c->stdout_file == NULL)
NULL, NULL, server_client_out_callback, c); fatal("fdopen(stdout) failed");
if (c->stdout_event == NULL)
fatalx("failed to create stdout event");
if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1)
fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK);
break; break;
case MSG_STDERR: case MSG_STDERR:
if (datalen != 0) if (datalen != 0)
@@ -723,14 +586,9 @@ server_client_msg_dispatch(struct client *c)
if (imsg.fd == -1) if (imsg.fd == -1)
fatalx("MSG_STDERR missing fd"); fatalx("MSG_STDERR missing fd");
c->stderr_fd = imsg.fd; c->stderr_file = fdopen(imsg.fd, "w");
c->stderr_event = bufferevent_new(c->stderr_fd, if (c->stderr_file == NULL)
NULL, NULL, server_client_err_callback, c); fatal("fdopen(stderr) failed");
if (c->stderr_event == NULL)
fatalx("failed to create stderr event");
if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1)
fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK);
break; break;
case MSG_RESIZE: case MSG_RESIZE:
if (datalen != 0) if (datalen != 0)
@@ -800,10 +658,12 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap); vfprintf(ctx->cmdclient->stderr_file, fmt, ap);
va_end(ap); va_end(ap);
bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1); fputc('\n', ctx->cmdclient->stderr_file);
fflush(ctx->cmdclient->stderr_file);
ctx->cmdclient->retcode = 1; ctx->cmdclient->retcode = 1;
} }
@@ -814,10 +674,11 @@ server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
va_end(ap); va_end(ap);
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); fputc('\n', ctx->cmdclient->stdout_file);
fflush(ctx->cmdclient->stdout_file);
} }
/* Callback to send print message to client, if not quiet. */ /* Callback to send print message to client, if not quiet. */
@@ -830,20 +691,22 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
return; return;
va_start(ap, fmt); va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
va_end(ap); va_end(ap);
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); fputc('\n', ctx->cmdclient->stderr_file);
fflush(ctx->cmdclient->stdout_file);
} }
/* Handle command message. */ /* Handle command message. */
void void
server_client_msg_command(struct client *c, struct msg_command_data *data) server_client_msg_command(struct client *c, struct msg_command_data *data)
{ {
struct cmd_ctx ctx; struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL; struct cmd_list *cmdlist = NULL;
int argc; struct msg_exit_data exitdata;
char **argv, *cause; int argc;
char **argv, *cause;
ctx.error = server_client_msg_error; ctx.error = server_client_msg_error;
ctx.print = server_client_msg_print; ctx.print = server_client_msg_print;
@@ -874,15 +737,18 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
} }
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
if (cmd_list_exec(cmdlist, &ctx) != 1) if (cmd_list_exec(cmdlist, &ctx) != 1) {
c->flags |= CLIENT_EXIT; exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
}
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return; return;
error: error:
if (cmdlist != NULL) if (cmdlist != NULL)
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
c->flags |= CLIENT_EXIT; exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
} }
/* Handle identify message. */ /* Handle identify message. */

View File

@@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.117 2010-12-25 23:44:37 tcunha Exp $ */ /* $Id: server-fn.c,v 1.108 2010-07-02 02:45:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,10 +30,13 @@ void server_callback_identify(int, short, void *);
void void
server_fill_environ(struct session *s, struct environ *env) server_fill_environ(struct session *s, struct environ *env)
{ {
char tmuxvar[MAXPATHLEN], *term; char tmuxvar[MAXPATHLEN], *term;
u_int idx;
if (session_index(s, &idx) != 0)
fatalx("session not found");
xsnprintf(tmuxvar, sizeof tmuxvar, xsnprintf(tmuxvar, sizeof tmuxvar,
"%s,%ld,%u", socket_path, (long) getpid(), s->idx); "%s,%ld,%u", socket_path, (long) getpid(), idx);
environ_set(env, "TMUX", tmuxvar); environ_set(env, "TMUX", tmuxvar);
term = options_get_string(&s->options, "default-terminal"); term = options_get_string(&s->options, "default-terminal");
@@ -172,6 +175,7 @@ void
server_status_window(struct window *w) server_status_window(struct window *w)
{ {
struct session *s; struct session *s;
u_int i;
/* /*
* This is slightly different. We want to redraw the status line of any * This is slightly different. We want to redraw the status line of any
@@ -179,8 +183,9 @@ server_status_window(struct window *w)
* current window. * current window.
*/ */
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (session_has(s, w) != NULL) s = ARRAY_ITEM(&sessions, i);
if (s != NULL && session_has(s, w) != NULL)
server_status_session(s); server_status_session(s);
} }
} }
@@ -239,15 +244,13 @@ server_lock_client(struct client *c)
void void
server_kill_window(struct window *w) server_kill_window(struct window *w)
{ {
struct session *s, *next_s; struct session *s;
struct winlink *wl; struct winlink *wl;
u_int i;
next_s = RB_MIN(sessions, &sessions); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
while (next_s != NULL) { s = ARRAY_ITEM(&sessions, i);
s = next_s; if (s == NULL || session_has(s, w) == NULL)
next_s = RB_NEXT(sessions, &sessions, s);
if (session_has(s, w) == NULL)
continue; continue;
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
if (session_detach(s, wl)) { if (session_detach(s, wl)) {
@@ -277,10 +280,8 @@ server_link_window(struct session *src, struct winlink *srcwl,
if (dstidx != -1) if (dstidx != -1)
dstwl = winlink_find_by_index(&dst->windows, dstidx); dstwl = winlink_find_by_index(&dst->windows, dstidx);
if (dstwl != NULL) { if (dstwl != NULL) {
if (dstwl->window == srcwl->window) { if (dstwl->window == srcwl->window)
xasprintf(cause, "same index: %d", dstidx); return (0);
return (-1);
}
if (killflag) { if (killflag) {
/* /*
* Can't use session_detach as it will destroy session * Can't use session_detach as it will destroy session
@@ -362,9 +363,11 @@ struct session *
server_next_session(struct session *s) server_next_session(struct session *s)
{ {
struct session *s_loop, *s_out; struct session *s_loop, *s_out;
u_int i;
s_out = NULL; s_out = NULL;
RB_FOREACH(s_loop, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s_loop = ARRAY_ITEM(&sessions, i);
if (s_loop == s) if (s_loop == s)
continue; continue;
if (s_out == NULL || if (s_out == NULL ||
@@ -392,9 +395,8 @@ server_destroy_session(struct session *s)
continue; continue;
if (s_new == NULL) { if (s_new == NULL) {
c->session = NULL; c->session = NULL;
c->flags |= CLIENT_EXIT; server_write_client(c, MSG_EXIT, NULL, 0);
} else { } else {
c->last_session = NULL;
c->session = s_new; c->session = s_new;
server_redraw_client(c); server_redraw_client(c);
} }
@@ -402,23 +404,6 @@ server_destroy_session(struct session *s)
recalculate_sizes(); recalculate_sizes();
} }
void
server_check_unattached (void)
{
struct session *s;
/*
* If any sessions are no longer attached and have destroy-unattached
* set, collect them.
*/
RB_FOREACH(s, sessions, &sessions) {
if (!(s->flags & SESSION_UNATTACHED))
continue;
if (options_get_number (&s->options, "destroy-unattached"))
session_destroy(s);
}
}
void void
server_set_identify(struct client *c) server_set_identify(struct client *c)
{ {

View File

@@ -1,4 +1,4 @@
/* $Id: server-window.c,v 1.19 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: server-window.c,v 1.15 2010-06-22 23:26:18 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,10 +26,34 @@
int server_window_backoff(struct window_pane *); int server_window_backoff(struct window_pane *);
int server_window_check_bell(struct session *, struct winlink *); int server_window_check_bell(struct session *, struct winlink *);
int server_window_check_activity(struct session *, struct winlink *); int server_window_check_activity(struct session *, struct winlink *);
int server_window_check_silence(struct session *, struct winlink *);
int server_window_check_content( int server_window_check_content(
struct session *, struct winlink *, struct window_pane *); struct session *, struct winlink *, struct window_pane *);
/* Check if this window should suspend reading. */
int
server_window_backoff(struct window_pane *wp)
{
struct client *c;
u_int i;
if (!window_pane_visible(wp))
return (0);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0)
continue;
if (c->session->curw->window != wp->window)
continue;
if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD)
return (1);
}
return (0);
}
/* Window functions that need to happen every loop. */ /* Window functions that need to happen every loop. */
void void
server_window_loop(void) server_window_loop(void)
@@ -38,21 +62,34 @@ server_window_loop(void)
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
u_int i; u_int i, j;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i); w = ARRAY_ITEM(&windows, i);
if (w == NULL) if (w == NULL)
continue; continue;
RB_FOREACH(s, sessions, &sessions) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
if (!(wp->flags & PANE_FREEZE)) {
if (server_window_backoff(wp))
bufferevent_disable(wp->event, EV_READ);
else
bufferevent_enable(wp->event, EV_READ);
}
}
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
s = ARRAY_ITEM(&sessions, j);
if (s == NULL)
continue;
wl = session_has(s, w); wl = session_has(s, w);
if (wl == NULL) if (wl == NULL)
continue; continue;
if (server_window_check_bell(s, wl) || if (server_window_check_bell(s, wl) ||
server_window_check_activity(s, wl) || server_window_check_activity(s, wl))
server_window_check_silence(s, wl))
server_status_session(s); server_status_session(s);
TAILQ_FOREACH(wp, &w->panes, entry) TAILQ_FOREACH(wp, &w->panes, entry)
server_window_check_content(s, wl, wp); server_window_check_content(s, wl, wp);
@@ -72,8 +109,10 @@ server_window_check_bell(struct session *s, struct winlink *wl)
if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
return (0); return (0);
if (s->curw != wl) if (s->curw == wl)
wl->flags |= WINLINK_BELL; return (0);
wl->flags |= WINLINK_BELL;
action = options_get_number(&s->options, "bell-action"); action = options_get_number(&s->options, "bell-action");
switch (action) { switch (action) {
@@ -150,55 +189,6 @@ server_window_check_activity(struct session *s, struct winlink *wl)
return (1); return (1);
} }
/* Check for silence in window. */
int
server_window_check_silence(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
struct timeval timer;
u_int i;
int silence_interval, timer_difference;
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0);
if (s->curw == wl) {
/*
* Reset the timer for this window if we've focused it. We
* don't want the timer tripping as soon as we've switched away
* from this window.
*/
if (gettimeofday(&w->silence_timer, NULL) != 0)
fatal("gettimeofday failed.");
return (0);
}
silence_interval = options_get_number(&w->options, "monitor-silence");
if (silence_interval == 0)
return (0);
if (gettimeofday(&timer, NULL) != 0)
fatal("gettimeofday");
timer_difference = timer.tv_sec - w->silence_timer.tv_sec;
if (timer_difference <= silence_interval)
return (0);
wl->flags |= WINLINK_SILENCE;
if (options_get_number(&s->options, "visual-silence")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
status_message_set(c, "Silence in window %u",
winlink_find_by_window(&s->windows, w)->idx);
}
}
return (1);
}
/* Check for content change in window. */ /* Check for content change in window. */
int int
server_window_check_content( server_window_check_content(

View File

@@ -1,4 +1,4 @@
/* $Id: server.c,v 1.249 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: server.c,v 1.242 2010-06-22 23:21:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -97,6 +97,8 @@ server_create_socket(void)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
server_update_socket(); server_update_socket();
@@ -105,13 +107,16 @@ server_create_socket(void)
/* Fork new server. */ /* Fork new server. */
int int
server_start(void) server_start(char *path)
{ {
struct window_pane *wp; struct window_pane *wp;
int pair[2]; int pair[2];
char *cause; char *cause;
struct timeval tv; struct timeval tv;
u_int i; u_int i;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
/* The first client is special and gets a socketpair; create it. */ /* The first client is special and gets a socketpair; create it. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
@@ -138,7 +143,7 @@ server_start(void)
/* event_init() was called in our parent, need to reinit. */ /* event_init() was called in our parent, need to reinit. */
if (event_reinit(ev_base) != 0) if (event_reinit(ev_base) != 0)
fatal("event_reinit failed"); fatal("event_reinit failed");
clear_signals(0); clear_signals();
logfile("server"); logfile("server");
log_debug("server started, pid %ld", (long) getpid()); log_debug("server started, pid %ld", (long) getpid());
@@ -146,17 +151,21 @@ server_start(void)
ARRAY_INIT(&windows); ARRAY_INIT(&windows);
ARRAY_INIT(&clients); ARRAY_INIT(&clients);
ARRAY_INIT(&dead_clients); ARRAY_INIT(&dead_clients);
RB_INIT(&sessions); ARRAY_INIT(&sessions);
RB_INIT(&dead_sessions); ARRAY_INIT(&dead_sessions);
TAILQ_INIT(&session_groups); TAILQ_INIT(&session_groups);
mode_key_init_trees(); mode_key_init_trees();
key_bindings_init(); key_bindings_init();
utf8_build(); utf8_build();
start_time = time(NULL); start_time = time(NULL);
log_debug("socket path %s", socket_path); socket_path = path;
#ifdef HAVE_SETPROCTITLE #ifdef HAVE_SETPROCTITLE
setproctitle("server (%s)", socket_path); if (realpath(socket_path, rpathbuf) == NULL)
strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
log_debug("socket path %s", socket_path);
setproctitle("server (%s)", rpathbuf);
#endif #endif
server_fd = server_create_socket(); server_fd = server_create_socket();
@@ -175,8 +184,8 @@ server_start(void)
* If there is a session already, put the current window and pane into * If there is a session already, put the current window and pane into
* more mode. * more mode.
*/ */
if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = RB_MIN(sessions, &sessions)->curw->window->active; wp = ARRAY_FIRST(&sessions)->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode); window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp); window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
@@ -217,14 +226,14 @@ server_loop(void)
} }
} }
/* Check if the server should be shutting down (no more clients or sessions). */ /* Check if the server should be shutting down (no more clients or windows). */
int int
server_should_shutdown(void) server_should_shutdown(void)
{ {
u_int i; u_int i;
if (!options_get_number(&global_options, "exit-unattached")) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (!RB_EMPTY(&sessions)) if (ARRAY_ITEM(&sessions, i) != NULL)
return (0); return (0);
} }
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -239,7 +248,7 @@ void
server_send_shutdown(void) server_send_shutdown(void)
{ {
struct client *c; struct client *c;
struct session *s, *next_s; struct session *s;
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -253,11 +262,9 @@ server_send_shutdown(void)
} }
} }
s = RB_MIN(sessions, &sessions); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
while (s != NULL) { if ((s = ARRAY_ITEM(&sessions, i)) != NULL)
next_s = RB_NEXT(sessions, &sessions, s); session_destroy(s);
session_destroy(s);
s = next_s;
} }
} }
@@ -265,19 +272,16 @@ server_send_shutdown(void)
void void
server_clean_dead(void) server_clean_dead(void)
{ {
struct session *s, *next_s; struct session *s;
struct client *c; struct client *c;
u_int i; u_int i;
s = RB_MIN(sessions, &dead_sessions); for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
while (s != NULL) { s = ARRAY_ITEM(&dead_sessions, i);
next_s = RB_NEXT(sessions, &dead_sessions, s); if (s == NULL || s->references != 0)
if (s->references == 0) { continue;
RB_REMOVE(sessions, &dead_sessions, s); ARRAY_SET(&dead_sessions, i, NULL);
xfree(s->name); xfree(s);
xfree(s);
}
s = next_s;
} }
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
@@ -294,13 +298,14 @@ void
server_update_socket(void) server_update_socket(void)
{ {
struct session *s; struct session *s;
u_int i;
static int last = -1; static int last = -1;
int n, mode; int n;
struct stat sb;
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (!(s->flags & SESSION_UNATTACHED)) { s = ARRAY_ITEM(&sessions, i);
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
n++; n++;
break; break;
} }
@@ -308,20 +313,10 @@ server_update_socket(void)
if (n != last) { if (n != last) {
last = n; last = n;
if (n != 0)
if (stat(socket_path, &sb) != 0) chmod(socket_path, S_IRWXU|S_IRWXG);
return; else
mode = sb.st_mode; chmod(socket_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
if (n != 0) {
if (mode & S_IRUSR)
mode |= S_IXUSR;
if (mode & S_IRGRP)
mode |= S_IXGRP;
if (mode & S_IROTH)
mode |= S_IXOTH;
} else
mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
chmod(socket_path, mode);
} }
} }
@@ -487,11 +482,15 @@ void
server_lock_server(void) server_lock_server(void)
{ {
struct session *s; struct session *s;
u_int i;
int timeout; int timeout;
time_t t; time_t t;
t = time(NULL); t = time(NULL);
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) { if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0) if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday failed");
@@ -512,11 +511,15 @@ void
server_lock_sessions(void) server_lock_sessions(void)
{ {
struct session *s; struct session *s;
u_int i;
int timeout; int timeout;
time_t t; time_t t;
t = time(NULL); t = time(NULL);
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) { if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0) if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday failed");

122
session.c
View File

@@ -1,4 +1,4 @@
/* $Id: session.c,v 1.83 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: session.c,v 1.77 2010-07-02 02:49:19 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,56 +29,24 @@
/* Global session list. */ /* Global session list. */
struct sessions sessions; struct sessions sessions;
struct sessions dead_sessions; struct sessions dead_sessions;
u_int next_session;
struct session_groups session_groups; struct session_groups session_groups;
struct winlink *session_next_alert(struct winlink *); struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct winlink *); struct winlink *session_previous_alert(struct winlink *);
RB_GENERATE(sessions, session, entry, session_cmp);
int
session_cmp(struct session *s1, struct session *s2)
{
return (strcmp(s1->name, s2->name));
}
/*
* Find if session is still alive. This is true if it is still on the global
* sessions list.
*/
int
session_alive(struct session *s)
{
struct session *s_loop;
RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s)
return (1);
}
return (0);
}
/* Find session by name. */ /* Find session by name. */
struct session * struct session *
session_find(const char *name) session_find(const char *name)
{
struct session s;
s.name = (char *) name;
return (RB_FIND(sessions, &sessions, &s));
}
/* Find session by index. */
struct session *
session_find_by_index(u_int idx)
{ {
struct session *s; struct session *s;
u_int i;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (s->idx == idx) s = ARRAY_ITEM(&sessions, i);
if (s != NULL && strcmp(s->name, name) == 0)
return (s); return (s);
} }
return (NULL); return (NULL);
} }
@@ -89,6 +57,7 @@ session_create(const char *name, const char *cmd, const char *cwd,
char **cause) char **cause)
{ {
struct session *s; struct session *s;
u_int i;
s = xmalloc(sizeof *s); s = xmalloc(sizeof *s);
s->references = 0; s->references = 0;
@@ -120,12 +89,19 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->sx = sx; s->sx = sx;
s->sy = sy; s->sy = sy;
s->idx = next_session++; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (ARRAY_ITEM(&sessions, i) == NULL) {
ARRAY_SET(&sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&sessions))
ARRAY_ADD(&sessions, s);
if (name != NULL) if (name != NULL)
s->name = xstrdup(name); s->name = xstrdup(name);
else else
xasprintf(&s->name, "%u", s->idx); xasprintf(&s->name, "%u", i);
RB_INSERT(sessions, &sessions, s);
if (cmd != NULL) { if (cmd != NULL) {
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
@@ -144,9 +120,15 @@ session_create(const char *name, const char *cmd, const char *cwd,
void void
session_destroy(struct session *s) session_destroy(struct session *s)
{ {
u_int i;
log_debug("session %s destroyed", s->name); log_debug("session %s destroyed", s->name);
RB_REMOVE(sessions, &sessions, s); if (session_index(s, &i) != 0)
fatalx("session not found");
ARRAY_SET(&sessions, i, NULL);
while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
ARRAY_TRUNC(&sessions, 1);
if (s->tio != NULL) if (s->tio != NULL)
xfree(s->tio); xfree(s->tio);
@@ -162,48 +144,28 @@ session_destroy(struct session *s)
winlink_remove(&s->windows, RB_ROOT(&s->windows)); winlink_remove(&s->windows, RB_ROOT(&s->windows));
xfree(s->cwd); xfree(s->cwd);
xfree(s->name);
RB_INSERT(sessions, &dead_sessions, s); for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
if (ARRAY_ITEM(&dead_sessions, i) == NULL) {
ARRAY_SET(&dead_sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&dead_sessions))
ARRAY_ADD(&dead_sessions, s);
s->flags |= SESSION_DEAD;
} }
/* Find the next usable session. */ /* Find session index. */
struct session * int
session_next_session(struct session *s) session_index(struct session *s, u_int *i)
{ {
struct session *s2; for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) {
if (s == ARRAY_ITEM(&sessions, *i))
if (RB_EMPTY(&sessions) || !session_alive(s)) return (0);
return (NULL); }
return (-1);
s2 = s;
do {
s2 = RB_NEXT(sessions, &sessions, s2);
if (s2 == NULL)
s2 = RB_MIN(sessions, &sessions);
} while (s2 != s);
if (s2 == s)
return (NULL);
return (s2);
}
/* Find the previous usable session. */
struct session *
session_previous_session(struct session *s)
{
struct session *s2;
if (RB_EMPTY(&sessions) || !session_alive(s))
return (NULL);
s2 = s;
do {
s2 = RB_PREV(sessions, &sessions, s2);
if (s2 == NULL)
s2 = RB_MAX(sessions, &sessions);
} while (s2 != s);
if (s2 == s)
return (NULL);
return (s2);
} }
/* Create a new window on a session. */ /* Create a new window on a session. */

View File

@@ -1,4 +1,4 @@
/* $Id: signal.c,v 1.3 2010-08-29 14:42:11 tcunha Exp $ */ /* $Id: signal.c,v 1.2 2010-05-14 14:35:26 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -62,7 +62,7 @@ set_signals(void(*handler)(int, short, unused void *))
} }
void void
clear_signals(int after_fork) clear_signals(void)
{ {
struct sigaction sigact; struct sigaction sigact;
@@ -79,25 +79,10 @@ clear_signals(int after_fork)
if (sigaction(SIGTSTP, &sigact, NULL) != 0) if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed"); fatal("sigaction failed");
if (after_fork) { event_del(&ev_sighup);
if (sigaction(SIGHUP, &sigact, NULL) != 0) event_del(&ev_sigchld);
fatal("sigaction failed"); event_del(&ev_sigcont);
if (sigaction(SIGCHLD, &sigact, NULL) != 0) event_del(&ev_sigterm);
fatal("sigaction failed"); event_del(&ev_sigusr1);
if (sigaction(SIGCONT, &sigact, NULL) != 0) event_del(&ev_sigwinch);
fatal("sigaction failed");
if (sigaction(SIGTERM, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGWINCH, &sigact, NULL) != 0)
fatal("sigaction failed");
} else {
event_del(&ev_sighup);
event_del(&ev_sigchld);
event_del(&ev_sigcont);
event_del(&ev_sigterm);
event_del(&ev_sigusr1);
event_del(&ev_sigwinch);
}
} }

View File

@@ -1,4 +1,4 @@
/* $Id: status.c,v 1.151 2010-12-11 16:15:02 nicm Exp $ */ /* $Id: status.c,v 1.149 2010-06-22 23:26:18 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -41,14 +41,9 @@ void status_replace1(struct client *,
struct winlink *, char **, char **, char *, size_t, int); struct winlink *, char **, char **, char *, size_t, int);
void status_message_callback(int, short, void *); void status_message_callback(int, short, void *);
const char *status_prompt_up_history(u_int *); void status_prompt_add_history(struct client *);
const char *status_prompt_down_history(u_int *);
void status_prompt_add_history(const char *);
char *status_prompt_complete(const char *); char *status_prompt_complete(const char *);
/* Status prompt history. */
ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER;
/* Retrieve options for left string. */ /* Retrieve options for left string. */
char * char *
status_redraw_get_left(struct client *c, status_redraw_get_left(struct client *c,
@@ -400,8 +395,6 @@ status_replace1(struct client *c,struct winlink *wl,
tmp[0] = '!'; tmp[0] = '!';
else if (wl->flags & WINLINK_ACTIVITY) else if (wl->flags & WINLINK_ACTIVITY)
tmp[0] = '#'; tmp[0] = '#';
else if (wl->flags & WINLINK_SILENCE)
tmp[0] = '~';
else if (wl == s->curw) else if (wl == s->curw)
tmp[0] = '*'; tmp[0] = '*';
else if (wl == TAILQ_FIRST(&s->lastw)) else if (wl == TAILQ_FIRST(&s->lastw))
@@ -865,7 +858,6 @@ status_prompt_key(struct client *c, int key)
{ {
struct paste_buffer *pb; struct paste_buffer *pb;
char *s, *first, *last, word[64], swapc; char *s, *first, *last, word[64], swapc;
const char *histstr;
u_char ch; u_char ch;
size_t size, n, off, idx; size_t size, n, off, idx;
@@ -978,20 +970,29 @@ status_prompt_key(struct client *c, int key)
} }
break; break;
case MODEKEYEDIT_HISTORYUP: case MODEKEYEDIT_HISTORYUP:
histstr = status_prompt_up_history(&c->prompt_hindex); if (ARRAY_LENGTH(&c->prompt_hdata) == 0)
if (histstr == NULL)
break; break;
xfree(c->prompt_buffer); xfree(c->prompt_buffer);
c->prompt_buffer = xstrdup(histstr);
c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata,
ARRAY_LENGTH(&c->prompt_hdata) - 1 - c->prompt_hindex));
if (c->prompt_hindex != ARRAY_LENGTH(&c->prompt_hdata) - 1)
c->prompt_hindex++;
c->prompt_index = strlen(c->prompt_buffer); c->prompt_index = strlen(c->prompt_buffer);
c->flags |= CLIENT_STATUS; c->flags |= CLIENT_STATUS;
break; break;
case MODEKEYEDIT_HISTORYDOWN: case MODEKEYEDIT_HISTORYDOWN:
histstr = status_prompt_down_history(&c->prompt_hindex);
if (histstr == NULL)
break;
xfree(c->prompt_buffer); xfree(c->prompt_buffer);
c->prompt_buffer = xstrdup(histstr);
if (c->prompt_hindex != 0) {
c->prompt_hindex--;
c->prompt_buffer = xstrdup(ARRAY_ITEM(
&c->prompt_hdata, ARRAY_LENGTH(
&c->prompt_hdata) - 1 - c->prompt_hindex));
} else
c->prompt_buffer = xstrdup("");
c->prompt_index = strlen(c->prompt_buffer); c->prompt_index = strlen(c->prompt_buffer);
c->flags |= CLIENT_STATUS; c->flags |= CLIENT_STATUS;
break; break;
@@ -1033,7 +1034,7 @@ status_prompt_key(struct client *c, int key)
break; break;
case MODEKEYEDIT_ENTER: case MODEKEYEDIT_ENTER:
if (*c->prompt_buffer != '\0') if (*c->prompt_buffer != '\0')
status_prompt_add_history(c->prompt_buffer); status_prompt_add_history(c);
if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0) if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0)
status_prompt_clear(c); status_prompt_clear(c);
break; break;
@@ -1069,56 +1070,20 @@ status_prompt_key(struct client *c, int key)
} }
} }
/* Get previous line from the history. */
const char *
status_prompt_up_history(u_int *idx)
{
u_int size;
/*
* History runs from 0 to size - 1.
*
* Index is from 0 to size. Zero is empty.
*/
size = ARRAY_LENGTH(&status_prompt_history);
if (size == 0 || *idx == size)
return (NULL);
(*idx)++;
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
}
/* Get next line from the history. */
const char *
status_prompt_down_history(u_int *idx)
{
u_int size;
size = ARRAY_LENGTH(&status_prompt_history);
if (size == 0 || *idx == 0)
return ("");
(*idx)--;
if (*idx == 0)
return ("");
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
}
/* Add line to the history. */ /* Add line to the history. */
void void
status_prompt_add_history(const char *line) status_prompt_add_history(struct client *c)
{ {
u_int size; if (ARRAY_LENGTH(&c->prompt_hdata) > 0 &&
strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0)
size = ARRAY_LENGTH(&status_prompt_history);
if (size > 0 && strcmp(ARRAY_LAST(&status_prompt_history), line) == 0)
return; return;
if (size == PROMPT_HISTORY) { if (ARRAY_LENGTH(&c->prompt_hdata) == PROMPT_HISTORY) {
xfree(ARRAY_FIRST(&status_prompt_history)); xfree(ARRAY_FIRST(&c->prompt_hdata));
ARRAY_REMOVE(&status_prompt_history, 0); ARRAY_REMOVE(&c->prompt_hdata, 0);
} }
ARRAY_ADD(&status_prompt_history, xstrdup(line)); ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer));
} }
/* Complete word. */ /* Complete word. */

169
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.280 2010-12-27 21:17:25 tcunha Exp $ .\" $Id: tmux.1,v 1.264 2010-07-17 14:39:01 tcunha Exp $
.\" .\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: December 10 2010 $ .Dd $Mdocdate: July 15 2010 $
.Dt TMUX 1 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@@ -23,7 +23,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm tmux .Nm tmux
.Bk -words .Bk -words
.Op Fl 28lquvV .Op Fl 28lquv
.Op Fl c Ar shell-command .Op Fl c Ar shell-command
.Op Fl f Ar file .Op Fl f Ar file
.Op Fl L Ar socket-name .Op Fl L Ar socket-name
@@ -198,10 +198,6 @@ and
files in the current directory, where files in the current directory, where
.Em PID .Em PID
is the PID of the server or client process. is the PID of the server or client process.
.It Fl V
Report the
.Nm
version.
.It Ar command Op Ar flags .It Ar command Op Ar flags
This specifies one of a set of commands used to control This specifies one of a set of commands used to control
.Nm , .Nm ,
@@ -252,8 +248,6 @@ Select windows 0 to 9.
Enter the Enter the
.Nm .Nm
command prompt. command prompt.
.It ;
Move to the previously active pane.
.It = .It =
Choose which buffer to paste interactively from a list. Choose which buffer to paste interactively from a list.
.It \&? .It \&?
@@ -286,8 +280,6 @@ Briefly display pane indexes.
Force redraw of the attached client. Force redraw of the attached client.
.It s .It s
Select a new session for the attached client interactively. Select a new session for the attached client interactively.
.It L
Switch the attached client back to the last session.
.It t .It t
Show the time. Show the time.
.It w .It w
@@ -515,7 +507,7 @@ when they are created with the
command, or later with the command, or later with the
.Ic attach-session .Ic attach-session
command. command.
Each session has one or more windows Each session has one of more windows
.Em linked .Em linked
into it. into it.
Windows may be linked to multiple sessions and are made up of one or Windows may be linked to multiple sessions and are made up of one or
@@ -668,7 +660,6 @@ Suspend a client by sending
.Dv SIGTSTP .Dv SIGTSTP
(tty stop). (tty stop).
.It Xo Ic switch-client .It Xo Ic switch-client
.Op Fl lnp
.Op Fl c Ar target-client .Op Fl c Ar target-client
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Xc .Xc
@@ -677,13 +668,6 @@ Switch the current session for client
.Ar target-client .Ar target-client
to to
.Ar target-session . .Ar target-session .
If
.Fl l ,
.Fl n
or
.Fl p
is used, the client is moved to the last, next or previous session
respectively.
.El .El
.Sh WINDOWS AND PANES .Sh WINDOWS AND PANES
A A
@@ -906,7 +890,6 @@ $ tmux list-windows
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0} layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0} $ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
.Ed .Ed
.Pp
.Nm .Nm
automatically adjusts the size of the layout for the current window size. automatically adjusts the size of the layout for the current window size.
Note that a layout cannot be applied to a window with more panes than that Note that a layout cannot be applied to a window with more panes than that
@@ -1048,9 +1031,6 @@ option kills all but the pane given with
Kill the current window or the window at Kill the current window or the window at
.Ar target-window , .Ar target-window ,
removing it from any sessions to which it is linked. removing it from any sessions to which it is linked.
.It Ic last-pane Op Fl t Ar target-window
.D1 (alias: Ic lastp )
Select the last (previously selected) pane.
.It Ic last-window Op Fl t Ar target-session .It Ic last-window Op Fl t Ar target-session
.D1 (alias: Ic last ) .D1 (alias: Ic last )
Select the last (previously selected) window. Select the last (previously selected) window.
@@ -1488,7 +1468,7 @@ All arguments are sent sequentially from first to last.
Send the prefix key to a window as if it was pressed. Send the prefix key to a window as if it was pressed.
If multiple prefix keys are configured, only the first is sent. If multiple prefix keys are configured, only the first is sent.
.It Xo Ic unbind-key .It Xo Ic unbind-key
.Op Fl acn .Op Fl cn
.Op Fl t Ar key-table .Op Fl t Ar key-table
.Ar key .Ar key
.Xc .Xc
@@ -1502,9 +1482,6 @@ the primary key bindings are modified; in this case, if
is specified, the command bound to is specified, the command bound to
.Ar key .Ar key
without a prefix (if any) is removed. without a prefix (if any) is removed.
If
.Fl a
is present, all key bindings are removed.
.Pp .Pp
If If
.Fl t .Fl t
@@ -1598,15 +1575,17 @@ Available window options are listed under
.Pp .Pp
Available server options are: Available server options are:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Ic detach-on-destroy
If on (the default), the client is detached when the session it is attached to
is destroyed.
If off, the client is switched to the most recently active of the remaining
sessions.
.It Ic escape-time .It Ic escape-time
Set the time in milliseconds for which Set the time in milliseconds for which
.Nm .Nm
waits after an escape is input to determine if it is part of a function or meta waits after an escape is input to determine if it is part of a function or meta
key sequences. key sequences.
The default is 500 milliseconds. The default is 500 milliseconds.
.It Ic exit-unattached
If enabled, the server will exit when there are no attached clients, rather
than when there are no attached sessions.
.It Ic quiet .It Ic quiet
Enable or disable the display of various informational messages (see also the Enable or disable the display of various informational messages (see also the
.Fl q .Fl q
@@ -1646,11 +1625,6 @@ The default is an empty string, which instructs
to create a login shell using the value of the to create a login shell using the value of the
.Ic default-shell .Ic default-shell
option. option.
.It Ic default-path Ar path
Set the default working directory for processes created from keys, or
interactively from the prompt.
The default is empty, which means to use the working directory of the shell
from which the server was started if it is available or the user's home if not.
.It Ic default-shell Ar path .It Ic default-shell Ar path
Specify the default shell. Specify the default shell.
This is used as the login shell for new windows when the This is used as the login shell for new windows when the
@@ -1667,6 +1641,11 @@ or
This option should be configured when This option should be configured when
.Nm .Nm
is used as a login shell. is used as a login shell.
.It Ic default-path Ar path
Set the default working directory for processes created from keys, or
interactively from the prompt.
The default is empty, which means to use the working directory of the shell
from which the server was started if it is available or the user's home if not.
.It Ic default-terminal Ar terminal .It Ic default-terminal Ar terminal
Set the default terminal for new windows created in this session - the Set the default terminal for new windows created in this session - the
default value of the default value of the
@@ -1679,14 +1658,6 @@ to work correctly, this
be set to be set to
.Ql screen .Ql screen
or a derivative of it. or a derivative of it.
.It Ic destroy-unattached
If enabled and the session is no longer attached to any clients, it is
destroyed.
.It Ic detach-on-destroy
If on (the default), the client is detached when the session it is attached to
is destroyed.
If off, the client is switched to the most recently active of the remaining
sessions.
.It Ic display-panes-active-colour Ar colour .It Ic display-panes-active-colour Ar colour
Set the colour used by the Set the colour used by the
.Ic display-panes .Ic display-panes
@@ -1783,12 +1754,12 @@ If on,
captures the mouse and when a window is split into multiple panes the mouse may captures the mouse and when a window is split into multiple panes the mouse may
be used to select the current pane. be used to select the current pane.
The mouse click is also passed through to the application as normal. The mouse click is also passed through to the application as normal.
.It Ic pane-active-border-bg Ar colour
.It Ic pane-active-border-fg Ar colour
Set the pane border colour for the currently active pane.
.It Ic pane-border-bg Ar colour
.It Ic pane-border-fg Ar colour .It Ic pane-border-fg Ar colour
.It Ic pane-border-bg Ar colour
Set the pane border colour for panes aside from the active pane. Set the pane border colour for panes aside from the active pane.
.It Ic pane-active-border-fg Ar colour
.It Ic pane-active-border-bg Ar colour
Set the pane border colour for the currently active pane.
.It Ic prefix Ar keys .It Ic prefix Ar keys
Set the keys accepted as a prefix key. Set the keys accepted as a prefix key.
.Ar keys .Ar keys
@@ -1861,12 +1832,7 @@ or right justified.
.Xc .Xc
Use vi or emacs-style Use vi or emacs-style
key bindings in the status line, for example at the command prompt. key bindings in the status line, for example at the command prompt.
The default is emacs, unless the Defaults to emacs.
.Ev VISUAL
or
.Ev EDITOR
environment variables are set and contain the string
.Ql vi .
.It Ic status-left Ar string .It Ic status-left Ar string
Display Display
.Ar string .Ar string
@@ -1943,10 +1909,10 @@ is not interpreted, to enable UTF-8, use the
option. option.
.It Ic status-left-attr Ar attributes .It Ic status-left-attr Ar attributes
Set the attribute of the left part of the status line. Set the attribute of the left part of the status line.
.It Ic status-left-bg Ar colour
Set the background colour of the left part of the status line.
.It Ic status-left-fg Ar colour .It Ic status-left-fg Ar colour
Set the foreground colour of the left part of the status line. Set the foreground colour of the left part of the status line.
.It Ic status-left-bg Ar colour
Set the background colour of the left part of the status line.
.It Ic status-left-length Ar length .It Ic status-left-length Ar length
Set the maximum Set the maximum
.Ar length .Ar length
@@ -1968,15 +1934,16 @@ character pairs are replaced, and UTF-8 is dependent on the
option. option.
.It Ic status-right-attr Ar attributes .It Ic status-right-attr Ar attributes
Set the attribute of the right part of the status line. Set the attribute of the right part of the status line.
.It Ic status-right-bg Ar colour
Set the background colour of the right part of the status line.
.It Ic status-right-fg Ar colour .It Ic status-right-fg Ar colour
Set the foreground colour of the right part of the status line. Set the foreground colour of the right part of the status line.
.It Ic status-right-bg Ar colour
Set the background colour of the right part of the status line.
.It Ic status-right-length Ar length .It Ic status-right-length Ar length
Set the maximum Set the maximum
.Ar length .Ar length
of the right component of the status bar. of the right component of the status bar.
The default is 40. The default is 40.
.Pp
.It Xo Ic status-utf8 .It Xo Ic status-utf8
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2035,8 +2002,7 @@ was given to the
.Ic set-environment .Ic set-environment
command). command).
The default is The default is
"DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID "DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION".
XAUTHORITY".
.It Xo Ic visual-activity .It Xo Ic visual-activity
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2061,12 +2027,6 @@ display a message when content is present in a window
for which the for which the
.Ic monitor-content .Ic monitor-content
window option is enabled. window option is enabled.
.It Xo Ic visual-silence
.Op Ic on | off
.Xc
If
.Ic monitor-silence
is enabled, prints a message after the interval has expired on a given window.
.El .El
.It Xo Ic set-window-option .It Xo Ic set-window-option
.Op Fl agu .Op Fl agu
@@ -2100,19 +2060,6 @@ this option is good for full-screen programs which support
.Dv SIGWINCH .Dv SIGWINCH
and poor for interactive programs such as shells. and poor for interactive programs such as shells.
.Pp .Pp
.It Xo Ic alternate-screen
.Op Ic on | off
.Xc
This option configures whether programs running inside
.Nm
may use the terminal alternate screen feature, which allows the
.Em smcup
and
.Em rmcup
.Xr terminfo 5
capabilities to be issued to preserve the existing window content on start and
restore it on exit.
.Pp
.It Xo Ic automatic-rename .It Xo Ic automatic-rename
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2123,8 +2070,7 @@ will attempt - on supported platforms - to rename the window to reflect the
command currently running in it. command currently running in it.
This flag is automatically disabled for an individual window when a name This flag is automatically disabled for an individual window when a name
is specified at creation with is specified at creation with
.Ic new-window .Ic new-window or
or
.Ic new-session , .Ic new-session ,
or later with or later with
.Ic rename-window . .Ic rename-window .
@@ -2151,8 +2097,8 @@ or
.Ar height . .Ar height .
A value of zero restores the default unlimited setting. A value of zero restores the default unlimited setting.
.Pp .Pp
.It Ic main-pane-height Ar height
.It Ic main-pane-width Ar width .It Ic main-pane-width Ar width
.It Ic main-pane-height Ar height
Set the width or height of the main (left or top) pane in the Set the width or height of the main (left or top) pane in the
.Ic main-horizontal .Ic main-horizontal
or or
@@ -2172,14 +2118,7 @@ Set window modes foreground colour.
.Op Ic vi | emacs .Op Ic vi | emacs
.Xc .Xc
Use vi or emacs-style key bindings in copy and choice modes. Use vi or emacs-style key bindings in copy and choice modes.
As with the Key bindings default to emacs.
.Ic status-keys
option, the default is emacs, unless
.Ev VISUAL
or
.Ev EDITOR
contains
.Ql vi .
.Pp .Pp
.It Xo Ic mode-mouse .It Xo Ic mode-mouse
.Op Ic on | off .Op Ic on | off
@@ -2202,35 +2141,6 @@ pattern
.Ar match-string .Ar match-string
appears in the window, it is highlighted in the status line. appears in the window, it is highlighted in the status line.
.Pp .Pp
.It Xo Ic monitor-silence
.Op Ic interval
.Xc
Monitor for silence (no activity) in the window within
.Ic interval
seconds.
Windows that have been silent for the interval are highlighted in the
status line.
An interval of zero disables the monitoring.
.Pp
.It Ic other-pane-height Ar height
Set the height of the other panes (not the main pane) in the
.Ic main-horizontal
layout.
If this option is set to 0 (the default), it will have no effect.
If both the
.Ic main-pane-height
and
.Ic other-pane-height
options are set, the main pane will grow taller to make the other panes the
specified height, but will never shrink to do so.
.Pp
.It Ic other-pane-width Ar width
Like
.Ic other-pane-height ,
but set the width of other panes in the
.Ic main-vertical
layout.
.Pp
.It Xo Ic remain-on-exit .It Xo Ic remain-on-exit
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2246,6 +2156,19 @@ command.
Duplicate input to any pane to all other panes in the same window (only Duplicate input to any pane to all other panes in the same window (only
for panes that are not in any special mode). for panes that are not in any special mode).
.Pp .Pp
.It Xo Ic alternate-screen
.Op Ic on | off
.Xc
This option configures whether programs running inside
.Nm
may use the terminal alternate screen feature, which allows the
.Em smcup
and
.Em rmcup
.Xr terminfo 5
capabilities to be issued to preserve the existing window content on start and
restore it on exit.
.Pp
.It Xo Ic utf8 .It Xo Ic utf8
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2346,9 +2269,9 @@ copies the environment into the
.Em global environment ; .Em global environment ;
in addition, each session has a in addition, each session has a
.Em session environment . .Em session environment .
When a window is created, the session and global environments are merged. When a window is created, the session and global environments are merged with
If a variable exists in both, the value from the session environment is used. the session environment overriding any variable present in both.
The result is the initial environment passed to the new process. This is the initial environment passed to the new process.
.Pp .Pp
The The
.Ic update-environment .Ic update-environment
@@ -2429,7 +2352,6 @@ The flag is one of the following symbols appended to the window name:
.It Li "#" Ta "Window is monitored and activity has been detected." .It Li "#" Ta "Window is monitored and activity has been detected."
.It Li "!" Ta "A bell has occurred in the window." .It Li "!" Ta "A bell has occurred in the window."
.It Li "+" Ta "Window is monitored for content and it has appeared." .It Li "+" Ta "Window is monitored for content and it has appeared."
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
.El .El
.Pp .Pp
The # symbol relates to the The # symbol relates to the
@@ -2647,6 +2569,7 @@ Set the contents of the specified buffer to
Display the contents of the specified buffer. Display the contents of the specified buffer.
.El .El
.Sh MISCELLANEOUS .Sh MISCELLANEOUS
.Pp
Miscellaneous commands are as follows: Miscellaneous commands are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Ic clock-mode Op Fl t Ar target-pane .It Ic clock-mode Op Fl t Ar target-pane

319
tmux.c
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.228 2010-12-27 21:22:24 tcunha Exp $ */ /* $Id: tmux.c,v 1.214 2010-07-17 14:36:41 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,13 +18,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <fcntl.h>
#include <pwd.h> #include <pwd.h>
#include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <syslog.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -33,6 +35,7 @@
extern char *malloc_options; extern char *malloc_options;
#endif #endif
char *cfg_file;
struct options global_options; /* server options */ struct options global_options; /* server options */
struct options global_s_options; /* session options */ struct options global_s_options; /* session options */
struct options global_w_options; /* window options */ struct options global_w_options; /* window options */
@@ -40,19 +43,27 @@ struct environ global_environ;
struct event_base *ev_base; struct event_base *ev_base;
char *cfg_file;
char *shell_cmd;
int debug_level; int debug_level;
time_t start_time; time_t start_time;
char socket_path[MAXPATHLEN]; char *socket_path;
int login_shell; int login_shell;
char *environ_path;
pid_t environ_pid; struct env_data {
u_int environ_idx; char *path;
pid_t pid;
u_int idx;
};
__dead void usage(void); __dead void usage(void);
void parseenvironment(void); void parse_env(struct env_data *);
char *makesocketpath(const char *); char *makesockpath(const char *);
__dead void shell_exec(const char *, const char *);
struct imsgbuf *main_ibuf;
void main_signal(int, short, unused void *);
void main_callback(int, short, void *);
void main_dispatch(const char *);
#ifndef HAVE_PROGNAME #ifndef HAVE_PROGNAME
char *__progname = (char *) "tmux"; char *__progname = (char *) "tmux";
@@ -62,7 +73,7 @@ __dead void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: %s [-28lquvV] [-c shell-command] [-f file] [-L socket-name]\n" "usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n", " [-S socket-path] [command [flags]]\n",
__progname); __progname);
exit(1); exit(1);
@@ -126,14 +137,14 @@ areshell(const char *shell)
} }
void void
parseenvironment(void) parse_env(struct env_data *data)
{ {
char *env, *path_pid, *pid_idx, buf[256]; char *env, *path_pid, *pid_idx, buf[256];
size_t len; size_t len;
const char *errstr; const char *errstr;
long long ll; long long ll;
environ_pid = -1; data->pid = -1;
if ((env = getenv("TMUX")) == NULL) if ((env = getenv("TMUX")) == NULL)
return; return;
@@ -146,9 +157,9 @@ parseenvironment(void)
/* path */ /* path */
len = path_pid - env; len = path_pid - env;
environ_path = xmalloc(len + 1); data->path = xmalloc (len + 1);
memcpy(environ_path, env, len); memcpy(data->path, env, len);
environ_path[len] = '\0'; data->path[len] = '\0';
/* pid */ /* pid */
len = pid_idx - path_pid - 1; len = pid_idx - path_pid - 1;
@@ -160,17 +171,17 @@ parseenvironment(void)
ll = strtonum(buf, 0, LONG_MAX, &errstr); ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
return; return;
environ_pid = ll; data->pid = ll;
/* idx */ /* idx */
ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr); ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
return; return;
environ_idx = ll; data->idx = ll;
} }
char * char *
makesocketpath(const char *label) makesockpath(const char *label)
{ {
char base[MAXPATHLEN], *path; char base[MAXPATHLEN], *path;
struct stat sb; struct stat sb;
@@ -202,7 +213,6 @@ shell_exec(const char *shell, const char *shellcmd)
{ {
const char *shellname, *ptr; const char *shellname, *ptr;
char *argv0; char *argv0;
int mode;
ptr = strrchr(shell, '/'); ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0') if (ptr != NULL && *(ptr + 1) != '\0')
@@ -215,14 +225,6 @@ shell_exec(const char *shell, const char *shellcmd)
xasprintf(&argv0, "%s", shellname); xasprintf(&argv0, "%s", shellname);
setenv("SHELL", shell, 1); setenv("SHELL", shell, 1);
if ((mode = fcntl(STDIN_FILENO, F_GETFL)) != -1)
fcntl(STDIN_FILENO, F_SETFL, mode & ~O_NONBLOCK);
if ((mode = fcntl(STDOUT_FILENO, F_GETFL)) != -1)
fcntl(STDOUT_FILENO, F_SETFL, mode & ~O_NONBLOCK);
if ((mode = fcntl(STDERR_FILENO, F_GETFL)) != -1)
fcntl(STDERR_FILENO, F_SETFL, mode & ~O_NONBLOCK);
closefrom(STDERR_FILENO + 1);
execl(shell, argv0, "-c", shellcmd, (char *) NULL); execl(shell, argv0, "-c", shellcmd, (char *) NULL);
fatal("execl failed"); fatal("execl failed");
} }
@@ -230,20 +232,30 @@ shell_exec(const char *shell, const char *shellcmd)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct passwd *pw; struct cmd_list *cmdlist;
struct options *oo, *so, *wo; struct cmd *cmd;
struct keylist *keylist; enum msgtype msg;
char *s, *path, *label, *home, **var; struct passwd *pw;
int opt, flags, quiet, keys; struct options *oo, *so, *wo;
struct keylist *keylist;
struct env_data envdata;
struct msg_command_data cmddata;
char *s, *shellcmd, *path, *label, *home, *cause;
char **var;
void *buf;
size_t len;
int opt, flags, quiet = 0, cmdflags = 0;
short events;
#if defined(DEBUG) && defined(__OpenBSD__) #if defined(DEBUG) && defined(__OpenBSD__)
malloc_options = (char *) "AFGJPX"; malloc_options = (char *) "AFGJPX";
#endif #endif
quiet = flags = 0; flags = 0;
label = path = NULL; shellcmd = label = path = NULL;
envdata.path = NULL;
login_shell = (**argv == '-'); login_shell = (**argv == '-');
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) { while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) {
switch (opt) { switch (opt) {
case '2': case '2':
flags |= IDENTIFY_256COLOURS; flags |= IDENTIFY_256COLOURS;
@@ -254,13 +266,10 @@ main(int argc, char **argv)
flags &= ~IDENTIFY_256COLOURS; flags &= ~IDENTIFY_256COLOURS;
break; break;
case 'c': case 'c':
if (shell_cmd != NULL) if (shellcmd != NULL)
xfree(shell_cmd); xfree(shellcmd);
shell_cmd = xstrdup(optarg); shellcmd = xstrdup(optarg);
break; break;
case 'V':
printf("%s %s\n", __progname, BUILD);
exit(0);
case 'f': case 'f':
if (cfg_file != NULL) if (cfg_file != NULL)
xfree(cfg_file); xfree(cfg_file);
@@ -295,7 +304,7 @@ main(int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (shell_cmd != NULL && argc != 0) if (shellcmd != NULL && argc != 0)
usage(); usage();
log_open_tty(debug_level); log_open_tty(debug_level);
@@ -325,7 +334,6 @@ main(int argc, char **argv)
oo = &global_options; oo = &global_options;
options_set_number(oo, "quiet", quiet); options_set_number(oo, "quiet", quiet);
options_set_number(oo, "escape-time", 500); options_set_number(oo, "escape-time", 500);
options_set_number(oo, "exit-unattached", 0);
options_init(&global_s_options, NULL); options_init(&global_s_options, NULL);
so = &global_s_options; so = &global_s_options;
@@ -336,7 +344,6 @@ main(int argc, char **argv)
options_set_string(so, "default-path", "%s", ""); options_set_string(so, "default-path", "%s", "");
options_set_string(so, "default-shell", "%s", getshell()); options_set_string(so, "default-shell", "%s", getshell());
options_set_string(so, "default-terminal", "screen"); options_set_string(so, "default-terminal", "screen");
options_set_number(so, "destroy-unattached", 0);
options_set_number(so, "detach-on-destroy", 1); options_set_number(so, "detach-on-destroy", 1);
options_set_number(so, "display-panes-active-colour", 1); options_set_number(so, "display-panes-active-colour", 1);
options_set_number(so, "display-panes-colour", 4); options_set_number(so, "display-panes-colour", 4);
@@ -365,6 +372,7 @@ main(int argc, char **argv)
options_set_number(so, "status-fg", 0); options_set_number(so, "status-fg", 0);
options_set_number(so, "status-interval", 15); options_set_number(so, "status-interval", 15);
options_set_number(so, "status-justify", 0); options_set_number(so, "status-justify", 0);
options_set_number(so, "status-keys", MODEKEY_EMACS);
options_set_string(so, "status-left", "[#S]"); options_set_string(so, "status-left", "[#S]");
options_set_number(so, "status-left-attr", 0); options_set_number(so, "status-left-attr", 0);
options_set_number(so, "status-left-bg", 8); options_set_number(so, "status-left-bg", 8);
@@ -377,15 +385,11 @@ main(int argc, char **argv)
options_set_number(so, "status-right-length", 40); options_set_number(so, "status-right-length", 40);
options_set_string(so, "terminal-overrides", options_set_string(so, "terminal-overrides",
"*88col*:colors=88,*256col*:colors=256"); "*88col*:colors=88,*256col*:colors=256");
options_set_string(so, "update-environment", options_set_string(so, "update-environment", "DISPLAY "
"DISPLAY " "WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION");
"SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION "
"WINDOWID "
"XAUTHORITY");
options_set_number(so, "visual-activity", 0); options_set_number(so, "visual-activity", 0);
options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-bell", 0);
options_set_number(so, "visual-content", 0); options_set_number(so, "visual-content", 0);
options_set_number(so, "visual-silence", 0);
keylist = xmalloc(sizeof *keylist); keylist = xmalloc(sizeof *keylist);
ARRAY_INIT(keylist); ARRAY_INIT(keylist);
@@ -402,16 +406,14 @@ main(int argc, char **argv)
options_set_number(wo, "force-height", 0); options_set_number(wo, "force-height", 0);
options_set_number(wo, "force-width", 0); options_set_number(wo, "force-width", 0);
options_set_number(wo, "main-pane-height", 24); options_set_number(wo, "main-pane-height", 24);
options_set_number(wo, "main-pane-width", 80); options_set_number(wo, "main-pane-width", 81);
options_set_number(wo, "mode-attr", 0); options_set_number(wo, "mode-attr", 0);
options_set_number(wo, "mode-bg", 3); options_set_number(wo, "mode-bg", 3);
options_set_number(wo, "mode-fg", 0); options_set_number(wo, "mode-fg", 0);
options_set_number(wo, "mode-keys", MODEKEY_EMACS);
options_set_number(wo, "mode-mouse", 0); options_set_number(wo, "mode-mouse", 0);
options_set_number(wo, "monitor-activity", 0); options_set_number(wo, "monitor-activity", 0);
options_set_string(wo, "monitor-content", "%s", ""); options_set_string(wo, "monitor-content", "%s", "");
options_set_number(wo, "monitor-silence", 0);
options_set_number(wo, "other-pane-height", 0);
options_set_number(wo, "other-pane-width", 0);
options_set_number(wo, "window-status-attr", 0); options_set_number(wo, "window-status-attr", 0);
options_set_number(wo, "window-status-bg", 8); options_set_number(wo, "window-status-bg", 8);
options_set_number(wo, "window-status-current-attr", 0); options_set_number(wo, "window-status-current-attr", 0);
@@ -436,17 +438,6 @@ main(int argc, char **argv)
options_set_number(wo, "utf8", 0); options_set_number(wo, "utf8", 0);
} }
keys = MODEKEY_EMACS;
if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
if (strrchr(s, '/') != NULL)
s = strrchr(s, '/') + 1;
if (strstr(s, "vi") != NULL)
keys = MODEKEY_VI;
}
options_set_number(so, "status-keys", keys);
options_set_number(wo, "mode-keys", keys);
/* Locate the configuration file. */
if (cfg_file == NULL) { if (cfg_file == NULL) {
home = getenv("HOME"); home = getenv("HOME");
if (home == NULL || *home == '\0') { if (home == NULL || *home == '\0') {
@@ -462,22 +453,21 @@ main(int argc, char **argv)
} }
/* /*
* Figure out the socket path. If specified on the command-line with -S * Figure out the socket path. If specified on the command-line with
* or -L, use it, otherwise try $TMUX or assume -L default. * -S or -L, use it, otherwise try $TMUX or assume -L default.
*/ */
parseenvironment(); parse_env(&envdata);
if (path == NULL) { if (path == NULL) {
/* If no -L, use the environment. */ /* No -L. Try $TMUX, or default. */
if (label == NULL) { if (label == NULL) {
if (environ_path != NULL) path = envdata.path;
path = xstrdup(environ_path); if (path == NULL)
else
label = xstrdup("default"); label = xstrdup("default");
} }
/* -L or default set. */ /* -L or default set. */
if (label != NULL) { if (label != NULL) {
if ((path = makesocketpath(label)) == NULL) { if ((path = makesockpath(label)) == NULL) {
log_warn("can't create socket"); log_warn("can't create socket");
exit(1); exit(1);
} }
@@ -485,16 +475,66 @@ main(int argc, char **argv)
} }
if (label != NULL) if (label != NULL)
xfree(label); xfree(label);
if (realpath(path, socket_path) == NULL)
strlcpy(socket_path, path, sizeof socket_path);
xfree(path);
#ifdef HAVE_SETPROCTITLE if (shellcmd != NULL) {
/* Set process title. */ msg = MSG_SHELL;
setproctitle("%s (%s)", __progname, socket_path); buf = NULL;
#endif len = 0;
} else {
cmddata.pid = envdata.pid;
cmddata.idx = envdata.idx;
/* Prepare command for server. */
cmddata.argc = argc;
if (cmd_pack_argv(
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
log_warnx("command too long");
exit(1);
}
msg = MSG_COMMAND;
buf = &cmddata;
len = sizeof cmddata;
}
if (shellcmd != NULL)
cmdflags |= CMD_STARTSERVER;
else if (argc == 0) /* new-session is the default */
cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
else {
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
log_warnx("%s", cause);
exit(1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST;
}
cmd_list_free(cmdlist);
}
/*
* Check if this could be a nested session, if the command can't nest:
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shellcmd == NULL && envdata.path != NULL &&
cmdflags & CMD_CANTNEST &&
(path == envdata.path || strcmp(path, envdata.path) == 0)) {
log_warnx("sessions should be nested with care. "
"unset $TMUX to force.");
exit(1);
}
/* Pass control to the client. */
#ifdef HAVE_BROKEN_KQUEUE #ifdef HAVE_BROKEN_KQUEUE
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0) if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
fatal("setenv failed"); fatal("setenv failed");
@@ -510,5 +550,116 @@ main(int argc, char **argv)
#ifdef HAVE_BROKEN_POLL #ifdef HAVE_BROKEN_POLL
unsetenv("EVENT_NOPOLL"); unsetenv("EVENT_NOPOLL");
#endif #endif
exit(client_main(argc, argv, flags)); set_signals(main_signal);
/* Initialise the client socket/start the server. */
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
exit(1);
xfree(path);
imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
events = EV_READ;
if (main_ibuf->w.queued > 0)
events |= EV_WRITE;
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
event_dispatch();
clear_signals();
client_main(); /* doesn't return */
}
/* ARGSUSED */
void
main_signal(int sig, unused short events, unused void *data)
{
int status;
switch (sig) {
case SIGTERM:
exit(1);
case SIGCHLD:
waitpid(WAIT_ANY, &status, WNOHANG);
break;
}
}
/* ARGSUSED */
void
main_callback(unused int fd, short events, void *data)
{
char *shellcmd = data;
if (events & EV_READ)
main_dispatch(shellcmd);
if (events & EV_WRITE) {
if (msgbuf_write(&main_ibuf->w) < 0)
fatalx("msgbuf_write failed");
}
events = EV_READ;
if (main_ibuf->w.queued > 0)
events |= EV_WRITE;
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
}
void
main_dispatch(const char *shellcmd)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) {
if ((n = imsg_get(main_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof exitdata) {
if (datalen != 0)
fatalx("bad MSG_EXIT size");
exit(0);
}
memcpy(&exitdata, imsg.data, sizeof exitdata);
exit(exitdata.retcode);
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_loopexit(NULL); /* move to client_main() */
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
exit(1);
case MSG_SHELL:
if (datalen != sizeof shelldata)
fatalx("bad MSG_SHELL size");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
clear_signals();
shell_exec(shelldata.shell, shellcmd);
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
} }

89
tmux.h
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.591 2010-12-22 15:36:44 tcunha Exp $ */ /* $Id: tmux.h,v 1.571 2010-07-17 14:38:13 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,7 @@
#include <limits.h> #include <limits.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <termios.h> #include <termios.h>
@@ -57,8 +58,8 @@ extern char **environ;
/* Automatic name refresh interval, in milliseconds. */ /* Automatic name refresh interval, in milliseconds. */
#define NAME_INTERVAL 500 #define NAME_INTERVAL 500
/* Maximum data to buffer for output before suspending writing to a tty. */ /* Maximum data to buffer for output before suspending reading from panes. */
#define BACKOFF_THRESHOLD 16384 #define BACKOFF_THRESHOLD 1024
/* /*
* Maximum sizes of strings in message data. Don't forget to bump * Maximum sizes of strings in message data. Don't forget to bump
@@ -828,10 +829,8 @@ TAILQ_HEAD(window_panes, window_pane);
struct window { struct window {
char *name; char *name;
struct event name_timer; struct event name_timer;
struct timeval silence_timer;
struct window_pane *active; struct window_pane *active;
struct window_pane *last;
struct window_panes panes; struct window_panes panes;
int lastlayout; int lastlayout;
@@ -842,9 +841,9 @@ struct window {
int flags; int flags;
#define WINDOW_BELL 0x1 #define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2 #define WINDOW_HIDDEN 0x2
#define WINDOW_REDRAW 0x4 #define WINDOW_ACTIVITY 0x4
#define WINDOW_SILENCE 0x8 #define WINDOW_REDRAW 0x8
struct options options; struct options options;
@@ -865,9 +864,7 @@ struct winlink {
#define WINLINK_BELL 0x1 #define WINLINK_BELL 0x1
#define WINLINK_ACTIVITY 0x2 #define WINLINK_ACTIVITY 0x2
#define WINLINK_CONTENT 0x4 #define WINLINK_CONTENT 0x4
#define WINLINK_SILENCE 0x8 #define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT)
#define WINLINK_ALERTFLAGS \
(WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT|WINLINK_SILENCE)
RB_ENTRY(winlink) entry; RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) sentry; TAILQ_ENTRY(winlink) sentry;
@@ -928,8 +925,6 @@ struct session_group {
TAILQ_HEAD(session_groups, session_group); TAILQ_HEAD(session_groups, session_group);
struct session { struct session {
u_int idx;
char *name; char *name;
char *cwd; char *cwd;
@@ -948,6 +943,7 @@ struct session {
struct paste_stack buffers; struct paste_stack buffers;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_DEAD 0x2
int flags; int flags;
struct termios *tio; struct termios *tio;
@@ -957,10 +953,8 @@ struct session {
int references; int references;
TAILQ_ENTRY(session) gentry; TAILQ_ENTRY(session) gentry;
RB_ENTRY(session) entry;
}; };
RB_HEAD(sessions, session); ARRAY_DECL(sessions, struct session *);
ARRAY_DECL(sessionslist, struct session *);
/* TTY information. */ /* TTY information. */
struct tty_key { struct tty_key {
@@ -977,8 +971,6 @@ struct tty_term {
char *name; char *name;
u_int references; u_int references;
char acs[UCHAR_MAX + 1][2];
struct tty_code codes[NTTYCODE]; struct tty_code codes[NTTYCODE];
#define TERM_256COLOURS 0x1 #define TERM_256COLOURS 0x1
@@ -1016,13 +1008,14 @@ struct tty {
struct grid_cell cell; struct grid_cell cell;
u_char acs[UCHAR_MAX + 1];
#define TTY_NOCURSOR 0x1 #define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2 #define TTY_FREEZE 0x2
#define TTY_ESCAPE 0x4 #define TTY_ESCAPE 0x4
#define TTY_UTF8 0x8 #define TTY_UTF8 0x8
#define TTY_STARTED 0x10 #define TTY_STARTED 0x10
#define TTY_OPENED 0x20 #define TTY_OPENED 0x20
#define TTY_BACKOFF 0x40
int flags; int flags;
int term_flags; int term_flags;
@@ -1102,17 +1095,9 @@ struct client {
char *cwd; char *cwd;
struct tty tty; struct tty tty;
FILE *stdin_file;
int stdin_fd; FILE *stdout_file;
void *stdin_data; FILE *stderr_file;
void (*stdin_callback)(struct client *, void *);
struct bufferevent *stdin_event;
int stdout_fd;
struct bufferevent *stdout_event;
int stderr_fd;
struct bufferevent *stderr_event;
struct event repeat_timer; struct event repeat_timer;
@@ -1122,7 +1107,7 @@ struct client {
#define CLIENT_TERMINAL 0x1 #define CLIENT_TERMINAL 0x1
#define CLIENT_PREFIX 0x2 #define CLIENT_PREFIX 0x2
#define CLIENT_EXIT 0x4 /* 0x4 unused */
#define CLIENT_REDRAW 0x8 #define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10 #define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ #define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */
@@ -1132,8 +1117,6 @@ struct client {
#define CLIENT_DEAD 0x200 #define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400 #define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800 #define CLIENT_READONLY 0x800
#define CLIENT_BACKOFF 0x1000
#define CLIENT_REDRAWWINDOW 0x2000
int flags; int flags;
struct event identify_timer; struct event identify_timer;
@@ -1148,15 +1131,16 @@ struct client {
int (*prompt_callbackfn)(void *, const char *); int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *); void (*prompt_freefn)(void *);
void *prompt_data; void *prompt_data;
u_int prompt_hindex;
#define PROMPT_SINGLE 0x1 #define PROMPT_SINGLE 0x1
int prompt_flags; int prompt_flags;
u_int prompt_hindex;
ARRAY_DECL(, char *) prompt_hdata;
struct mode_key_data prompt_mdata; struct mode_key_data prompt_mdata;
struct session *session; struct session *session;
struct session *last_session;
int references; int references;
}; };
@@ -1295,23 +1279,19 @@ extern struct options global_w_options;
extern struct environ global_environ; extern struct environ global_environ;
extern struct event_base *ev_base; extern struct event_base *ev_base;
extern char *cfg_file; extern char *cfg_file;
extern char *shell_cmd;
extern int debug_level; extern int debug_level;
extern int be_quiet;
extern time_t start_time; extern time_t start_time;
extern char socket_path[MAXPATHLEN]; extern char *socket_path;
extern int login_shell; extern int login_shell;
extern char *environ_path;
extern pid_t environ_pid;
extern u_int environ_idx;
void logfile(const char *); void logfile(const char *);
const char *getshell(void); const char *getshell(void);
int checkshell(const char *); int checkshell(const char *);
int areshell(const char *); int areshell(const char *);
__dead void shell_exec(const char *, const char *);
/* cfg.c */ /* cfg.c */
extern int cfg_finished; extern int cfg_finished;
extern struct causelist cfg_causes; struct causelist cfg_causes;
void printflike2 cfg_add_cause(struct causelist *, const char *, ...); void printflike2 cfg_add_cause(struct causelist *, const char *, ...);
int load_cfg(const char *, struct cmd_ctx *, struct causelist *); int load_cfg(const char *, struct cmd_ctx *, struct causelist *);
@@ -1380,6 +1360,7 @@ void environ_push(struct environ *);
/* tty.c */ /* tty.c */
void tty_raw(struct tty *, const char *); void tty_raw(struct tty *, const char *);
u_char tty_get_acs(struct tty *, u_char);
void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes(struct tty *, const struct grid_cell *);
void tty_reset(struct tty *); void tty_reset(struct tty *);
void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int);
@@ -1433,9 +1414,6 @@ const char *tty_term_string2(
int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_number(struct tty_term *, enum tty_code_code);
int tty_term_flag(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code);
/* tty-acs.c */
const char *tty_acs_get(struct tty *, u_char);
/* tty-keys.c */ /* tty-keys.c */
void tty_keys_init(struct tty *); void tty_keys_init(struct tty *);
void tty_keys_free(struct tty *); void tty_keys_free(struct tty *);
@@ -1467,7 +1445,6 @@ const char *cmd_set_option_print(
/* cmd.c */ /* cmd.c */
int cmd_pack_argv(int, char **, char *, size_t); int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***); int cmd_unpack_argv(char *, size_t, int, char ***);
char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **); void cmd_free_argv(int, char **);
struct cmd *cmd_parse(int, char **, char **); struct cmd *cmd_parse(int, char **, char **);
int cmd_exec(struct cmd *, struct cmd_ctx *); int cmd_exec(struct cmd *, struct cmd_ctx *);
@@ -1512,7 +1489,6 @@ extern const struct cmd_entry cmd_kill_pane_entry;
extern const struct cmd_entry cmd_kill_server_entry; extern const struct cmd_entry cmd_kill_server_entry;
extern const struct cmd_entry cmd_kill_session_entry; extern const struct cmd_entry cmd_kill_session_entry;
extern const struct cmd_entry cmd_kill_window_entry; extern const struct cmd_entry cmd_kill_window_entry;
extern const struct cmd_entry cmd_last_pane_entry;
extern const struct cmd_entry cmd_last_window_entry; extern const struct cmd_entry cmd_last_window_entry;
extern const struct cmd_entry cmd_link_window_entry; extern const struct cmd_entry cmd_link_window_entry;
extern const struct cmd_entry cmd_list_buffers_entry; extern const struct cmd_entry cmd_list_buffers_entry;
@@ -1608,7 +1584,8 @@ void cmd_buffer_free(struct cmd *);
size_t cmd_buffer_print(struct cmd *, char *, size_t); size_t cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */ /* client.c */
int client_main(int, char **, int); struct imsgbuf *client_init(char *, int, int);
__dead void client_main(void);
/* key-bindings.c */ /* key-bindings.c */
extern struct key_bindings key_bindings; extern struct key_bindings key_bindings;
@@ -1631,7 +1608,7 @@ const char *key_string_lookup_key(int);
/* server.c */ /* server.c */
extern struct clients clients; extern struct clients clients;
extern struct clients dead_clients; extern struct clients dead_clients;
int server_start(void); int server_start(char *);
void server_update_socket(void); void server_update_socket(void);
/* server-client.c */ /* server-client.c */
@@ -1670,7 +1647,6 @@ void server_unlink_window(struct session *, struct winlink *);
void server_destroy_pane(struct window_pane *); void server_destroy_pane(struct window_pane *);
void server_destroy_session_group(struct session *); void server_destroy_session_group(struct session *);
void server_destroy_session(struct session *); void server_destroy_session(struct session *);
void server_check_unattached (void);
void server_set_identify(struct client *); void server_set_identify(struct client *);
void server_clear_identify(struct client *); void server_clear_identify(struct client *);
void server_update_event(struct client *); void server_update_event(struct client *);
@@ -1836,7 +1812,9 @@ int screen_check_selection(struct screen *, u_int, u_int);
/* window.c */ /* window.c */
extern struct windows windows; extern struct windows windows;
int window_cmp(struct window *, struct window *);
int winlink_cmp(struct winlink *, struct winlink *); int winlink_cmp(struct winlink *, struct winlink *);
RB_PROTOTYPE(windows, window, entry, window_cmp);
RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp);
struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_index(struct winlinks *, int);
struct winlink *winlink_find_by_window(struct winlinks *, struct window *); struct winlink *winlink_find_by_window(struct winlinks *, struct window *);
@@ -1962,24 +1940,19 @@ void queue_window_name(struct window *);
char *default_window_name(struct window *); char *default_window_name(struct window *);
/* signal.c */ /* signal.c */
void set_signals(void(*)(int, short, void *)); void set_signals(void(*handler)(int, short, unused void *));
void clear_signals(int); void clear_signals(void);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;
extern struct sessions dead_sessions; extern struct sessions dead_sessions;
extern struct session_groups session_groups; extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);
struct session *session_find(const char *); struct session *session_find(const char *);
struct session *session_find_by_index(u_int);
struct session *session_create(const char *, const char *, const char *, struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int, struct environ *, struct termios *, int, u_int, u_int,
char **); char **);
void session_destroy(struct session *); void session_destroy(struct session *);
struct session *session_next_session(struct session *); int session_index(struct session *, u_int *);
struct session *session_previous_session(struct session *);
struct winlink *session_new(struct session *, struct winlink *session_new(struct session *,
const char *, const char *, const char *, int, char **); const char *, const char *, const char *, int, char **);
struct winlink *session_attach( struct winlink *session_attach(

View File

@@ -1,5 +0,0 @@
# $Id: check-compat.sh,v 1.1 2010-10-24 00:42:04 tcunha Exp $
grep "#include" compat.h|while read line; do
grep "$line" *.[ch] compat/*.[ch]
done

View File

@@ -1,6 +1,6 @@
# $Id: dist.mk,v 1.11 2010-12-27 21:32:16 tcunha Exp $ # $Id: dist.mk,v 1.9 2010-07-18 13:36:52 tcunha Exp $
VERSION= 1.4 VERSION= 1.3
DISTDIR= tmux-${VERSION} DISTDIR= tmux-${VERSION}
DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \ DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \
@@ -20,7 +20,7 @@ dist:
upload-index.html: update-index.html upload-index.html: update-index.html
scp www/index.html www/main.css www/images/*.png \ scp www/index.html www/main.css www/images/*.png \
${USER},tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs nicm,tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
rm -f www/index.html www/images/small-* rm -f www/index.html www/images/small-*
update-index.html: update-index.html:

View File

@@ -1,31 +0,0 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int
main(void)
{
time_t t;
int i;
setvbuf(stdout, NULL, _IONBF, 0);
t = time(NULL);
srandom((u_int) t);
for (;;) {
putchar('\033');
for (i = 0; i < random() % 25; i++) {
if (i > 22)
putchar(';');
else
putchar(random() % 256);
}
/* usleep(100); */
}
}

View File

@@ -1,97 +0,0 @@
/* $Id: tty-acs.c,v 1.1 2010-09-18 15:43:53 tcunha Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
int tty_acs_cmp(const void *, const void *);
/* Table mapping ACS entries to UTF-8. */
struct tty_acs_entry {
u_char key;
const char *string;
};
const struct tty_acs_entry tty_acs_table[] = {
{ '+', "\342\206\222" },
{ ',', "\342\206\220" },
{ '-', "\342\206\221" },
{ '.', "\342\206\223" },
{ '0', "\342\226\256" },
{ '`', "\342\227\206" },
{ 'a', "\342\226\222" },
{ 'f', "\302\260" },
{ 'g', "\302\261" },
{ 'h', "\342\226\222" },
{ 'i', "\342\230\203" },
{ 'j', "\342\224\230" },
{ 'k', "\342\224\220" },
{ 'l', "\342\224\214" },
{ 'm', "\342\224\224" },
{ 'n', "\342\224\274" },
{ 'o', "\342\216\272" },
{ 'p', "\342\216\273" },
{ 'q', "\342\224\200" },
{ 'r', "\342\216\274" },
{ 's', "\342\216\275" },
{ 't', "\342\224\234" },
{ 'u', "\342\224\244" },
{ 'v', "\342\224\264" },
{ 'w', "\342\224\254" },
{ 'x', "\342\224\202" },
{ 'y', "\342\211\244" },
{ 'z', "\342\211\245" },
{ '{', "\317\200" },
{ '|', "\342\211\240" },
{ '}', "\302\243" },
{ '~', "\302\267" }
};
int
tty_acs_cmp(const void *key, const void *value)
{
const struct tty_acs_entry *entry = value;
u_char ch;
ch = *(u_char *) key;
return (ch - entry->key);
}
/* Retrieve ACS to output as a string. */
const char *
tty_acs_get(struct tty *tty, u_char ch)
{
struct tty_acs_entry *entry;
/* If not a UTF-8 terminal, use the ACS set. */
if (!(tty->flags & TTY_UTF8)) {
if (tty->term->acs[ch][0] == '\0')
return (NULL);
return (&tty->term->acs[ch][0]);
}
/* Otherwise look up the UTF-8 translation. */
entry = bsearch(&ch,
tty_acs_table, nitems(tty_acs_table), sizeof tty_acs_table[0],
tty_acs_cmp);
if (entry == NULL)
return (NULL);
return (entry->string);
}

View File

@@ -1,4 +1,4 @@
/* $Id: tty-term.c,v 1.43 2010-09-18 15:43:53 tcunha Exp $ */ /* $Id: tty-term.c,v 1.41 2009-12-18 07:42:30 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -252,8 +252,7 @@ tty_term_override(struct tty_term *term, const char *overrides)
} else if (entstr[strlen(entstr) - 1] == '@') { } else if (entstr[strlen(entstr) - 1] == '@') {
entstr[strlen(entstr) - 1] = '\0'; entstr[strlen(entstr) - 1] = '\0';
removeflag = 1; removeflag = 1;
} else }
continue;
for (i = 0; i < NTTYCODE; i++) { for (i = 0; i < NTTYCODE; i++) {
ent = &tty_term_codes[i]; ent = &tty_term_codes[i];
@@ -305,7 +304,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
u_int i; u_int i;
int n, error; int n, error;
char *s; char *s;
const char *acs;
SLIST_FOREACH(term, &tty_terms, entry) { SLIST_FOREACH(term, &tty_terms, entry) {
if (strcmp(term->name, name) == 0) { if (strcmp(term->name, name) == 0) {
@@ -319,7 +317,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
term->name = xstrdup(name); term->name = xstrdup(name);
term->references = 1; term->references = 1;
term->flags = 0; term->flags = 0;
memset(term->codes, 0, sizeof term->codes); memset(&term->codes, 0, sizeof term->codes);
SLIST_INSERT_HEAD(&tty_terms, term, entry); SLIST_INSERT_HEAD(&tty_terms, term, entry);
/* Set up curses terminal. */ /* Set up curses terminal. */
@@ -417,15 +415,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
if (!tty_term_flag(term, TTYC_XENL)) if (!tty_term_flag(term, TTYC_XENL))
term->flags |= TERM_EARLYWRAP; term->flags |= TERM_EARLYWRAP;
/* Generate ACS table. If none is present, use nearest ASCII. */
memset(term->acs, 0, sizeof term->acs);
if (tty_term_has(term, TTYC_ACSC))
acs = tty_term_string(term, TTYC_ACSC);
else
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
term->acs[(u_char) acs[0]][0] = acs[1];
return (term); return (term);
error: error:

66
tty.c
View File

@@ -1,4 +1,4 @@
/* $Id: tty.c,v 1.197 2010-12-06 21:57:56 nicm Exp $ */ /* $Id: tty.c,v 1.192 2010-06-06 00:30:34 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,8 @@
void tty_read_callback(struct bufferevent *, void *); void tty_read_callback(struct bufferevent *, void *);
void tty_error_callback(struct bufferevent *, short, void *); void tty_error_callback(struct bufferevent *, short, void *);
void tty_fill_acs(struct tty *);
int tty_try_256(struct tty *, u_char, const char *); int tty_try_256(struct tty *, u_char, const char *);
int tty_try_88(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *);
@@ -46,9 +48,6 @@ void tty_emulate_repeat(
void tty_cell(struct tty *, void tty_cell(struct tty *,
const struct grid_cell *, const struct grid_utf8 *); const struct grid_cell *, const struct grid_utf8 *);
#define tty_use_acs(tty) \
(tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
void void
tty_init(struct tty *tty, int fd, char *term) tty_init(struct tty *tty, int fd, char *term)
{ {
@@ -61,6 +60,9 @@ tty_init(struct tty *tty, int fd, char *term)
tty->termname = xstrdup("unknown"); tty->termname = xstrdup("unknown");
else else
tty->termname = xstrdup(term); tty->termname = xstrdup(term);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
tty->fd = fd; tty->fd = fd;
if ((path = ttyname(fd)) == NULL) if ((path = ttyname(fd)) == NULL)
@@ -141,6 +143,8 @@ tty_open(struct tty *tty, const char *overrides, char **cause)
tty_keys_init(tty); tty_keys_init(tty);
tty_fill_acs(tty);
return (0); return (0);
} }
@@ -197,8 +201,7 @@ tty_start_tty(struct tty *tty)
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
tty_putcode(tty, TTYC_RMKX); tty_putcode(tty, TTYC_RMKX);
if (tty_use_acs(tty)) tty_putcode(tty, TTYC_ENACS);
tty_putcode(tty, TTYC_ENACS);
tty_putcode(tty, TTYC_CLEAR); tty_putcode(tty, TTYC_CLEAR);
tty_putcode(tty, TTYC_CNORM); tty_putcode(tty, TTYC_CNORM);
@@ -239,8 +242,7 @@ tty_stop_tty(struct tty *tty)
return; return;
tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
if (tty_use_acs(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
@@ -255,6 +257,30 @@ tty_stop_tty(struct tty *tty)
fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK); fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK);
} }
void
tty_fill_acs(struct tty *tty)
{
const char *ptr;
memset(tty->acs, 0, sizeof tty->acs);
if (!tty_term_has(tty->term, TTYC_ACSC))
return;
ptr = tty_term_string(tty->term, TTYC_ACSC);
if (strlen(ptr) % 2 != 0)
return;
for (; *ptr != '\0'; ptr += 2)
tty->acs[(u_char) ptr[0]] = ptr[1];
}
u_char
tty_get_acs(struct tty *tty, u_char ch)
{
if (tty->acs[ch] != '\0')
return (tty->acs[ch]);
return (ch);
}
void void
tty_close(struct tty *tty) tty_close(struct tty *tty)
{ {
@@ -334,17 +360,11 @@ tty_puts(struct tty *tty, const char *s)
void void
tty_putc(struct tty *tty, u_char ch) tty_putc(struct tty *tty, u_char ch)
{ {
const char *acs; u_int sx;
u_int sx;
if (tty->cell.attr & GRID_ATTR_CHARSET) { if (tty->cell.attr & GRID_ATTR_CHARSET)
acs = tty_acs_get(tty, ch); ch = tty_get_acs(tty, ch);
if (acs != NULL) bufferevent_write(tty->event, &ch, 1);
bufferevent_write(tty->event, acs, strlen(acs));
else
bufferevent_write(tty->event, &ch, 1);
} else
bufferevent_write(tty->event, &ch, 1);
if (ch >= 0x20 && ch != 0x7f) { if (ch >= 0x20 && ch != 0x7f) {
sx = tty->sx; sx = tty->sx;
@@ -547,7 +567,7 @@ tty_write(void (*cmdfn)(
if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW)
return; return;
if (!window_pane_visible(wp)) if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp))
return; return;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -558,9 +578,7 @@ tty_write(void (*cmdfn)(
continue; continue;
if (c->session->curw->window == wp->window) { if (c->session->curw->window == wp->window) {
if (c->tty.term == NULL) if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL)
continue;
if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF))
continue; continue;
cmdfn(&c->tty, ctx); cmdfn(&c->tty, ctx);
} }
@@ -977,7 +995,7 @@ tty_reset(struct tty *tty)
if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0) if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0)
return; return;
if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty)) if (tty_term_has(tty->term, TTYC_RMACS) && gc->attr & GRID_ATTR_CHARSET)
tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_RMACS);
tty_putcode(tty, TTYC_SGR0); tty_putcode(tty, TTYC_SGR0);
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
@@ -1214,7 +1232,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc)
} }
if (changed & GRID_ATTR_HIDDEN) if (changed & GRID_ATTR_HIDDEN)
tty_putcode(tty, TTYC_INVIS); tty_putcode(tty, TTYC_INVIS);
if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty)) if (changed & GRID_ATTR_CHARSET)
tty_putcode(tty, TTYC_SMACS); tty_putcode(tty, TTYC_SMACS);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.125 2010-12-11 17:57:28 nicm Exp $ */ /* $Id: window-copy.c,v 1.121 2010-07-02 02:56:07 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -171,8 +171,7 @@ window_copy_init(struct window_pane *wp)
data->searchstr = NULL; data->searchstr = NULL;
wp->flags |= PANE_FREEZE; wp->flags |= PANE_FREEZE;
if (wp->fd != -1) bufferevent_disable(wp->event, EV_READ|EV_WRITE);
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
data->jumptype = WINDOW_COPY_OFF; data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = '\0'; data->jumpchar = '\0';
@@ -235,8 +234,7 @@ window_copy_free(struct window_pane *wp)
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
wp->flags &= ~PANE_FREEZE; wp->flags &= ~PANE_FREEZE;
if (wp->fd != -1) bufferevent_enable(wp->event, EV_READ|EV_WRITE);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
if (data->searchstr != NULL) if (data->searchstr != NULL)
xfree(data->searchstr); xfree(data->searchstr);
@@ -342,8 +340,6 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
data->cy = sy - 1; data->cy = sy - 1;
if (data->cx > sx) if (data->cx > sx)
data->cx = sx; data->cx = sx;
if (data->oy > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
window_copy_clear_selection(wp); window_copy_clear_selection(wp);
@@ -1057,8 +1053,6 @@ window_copy_write_line(
if (py == 0) { if (py == 0) {
size = xsnprintf(hdr, sizeof hdr, size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->oy, screen_hsize(data->backing)); "[%u/%u]", data->oy, screen_hsize(data->backing));
if (size > screen_size_x(s))
size = screen_size_x(s);
screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr); screen_write_puts(ctx, &gc, "%s", hdr);
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) { } else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
@@ -1267,8 +1261,8 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess)
/* Cursor is on the left. */ /* Cursor is on the left. */
lastex = data->selx + 1; lastex = data->selx + 1;
restex = data->selx + 1; restex = data->selx + 1;
firstsx = data->cx; firstsx = data->cx + 1;
restsx = data->cx; restsx = data->cx + 1;
} }
} else { } else {
/* /*

View File

@@ -1,4 +1,4 @@
/* $Id: window.c,v 1.142 2010-12-06 22:52:21 nicm Exp $ */ /* $Id: window.c,v 1.134 2010-07-17 14:38:13 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,6 +24,7 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <pwd.h> #include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@@ -322,9 +323,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
void void
window_set_active_pane(struct window *w, struct window_pane *wp) window_set_active_pane(struct window *w, struct window_pane *wp)
{ {
if (wp == w->active)
return;
w->last = w->active;
w->active = wp; w->active = wp;
while (!window_pane_visible(w->active)) { while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry); w->active = TAILQ_PREV(w->active, window_panes, entry);
@@ -341,7 +339,7 @@ window_set_active_at(struct window *w, u_int x, u_int y)
struct window_pane *wp; struct window_pane *wp;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == w->active || !window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
if (x < wp->xoff || x >= wp->xoff + wp->sx) if (x < wp->xoff || x >= wp->xoff + wp->sx)
continue; continue;
@@ -368,16 +366,9 @@ window_add_pane(struct window *w, u_int hlimit)
void void
window_remove_pane(struct window *w, struct window_pane *wp) window_remove_pane(struct window *w, struct window_pane *wp)
{ {
if (wp == w->active) { w->active = TAILQ_PREV(wp, window_panes, entry);
w->active = w->last; if (w->active == NULL)
w->last = NULL; w->active = TAILQ_NEXT(wp, entry);
if (w->active == NULL) {
w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_NEXT(wp, entry);
}
} else if (wp == w->last)
w->last = NULL;
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
window_pane_destroy(wp); window_pane_destroy(wp);
@@ -502,8 +493,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
void void
window_pane_destroy(struct window_pane *wp) window_pane_destroy(struct window_pane *wp)
{ {
window_pane_reset_mode(wp);
if (wp->fd != -1) { if (wp->fd != -1) {
close(wp->fd); close(wp->fd);
bufferevent_free(wp->event); bufferevent_free(wp->event);
@@ -511,6 +500,7 @@ window_pane_destroy(struct window_pane *wp)
input_free(wp); input_free(wp);
window_pane_reset_mode(wp);
screen_free(&wp->base); screen_free(&wp->base);
if (wp->saved_grid != NULL) if (wp->saved_grid != NULL)
grid_destroy(wp->saved_grid); grid_destroy(wp->saved_grid);
@@ -580,11 +570,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0) if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
closefrom(STDERR_FILENO + 1);
environ_push(env); environ_push(env);
clear_signals(1); clear_signals();
log_close(); log_close();
if (*wp->cmd != '\0') { if (*wp->cmd != '\0') {
@@ -612,6 +600,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
wp->event = bufferevent_new(wp->fd, wp->event = bufferevent_new(wp->fd,
window_pane_read_callback, NULL, window_pane_error_callback, wp); window_pane_read_callback, NULL, window_pane_error_callback, wp);
bufferevent_enable(wp->event, EV_READ|EV_WRITE); bufferevent_enable(wp->event, EV_READ|EV_WRITE);
@@ -636,14 +626,6 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data)
input_parse(wp); input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
/*
* If we get here, we're not outputting anymore, so set the silence
* flag on the window.
*/
wp->window->flags |= WINDOW_SILENCE;
if (gettimeofday(&wp->window->silence_timer, NULL) != 0)
fatal("gettimeofday failed.");
} }
/* ARGSUSED */ /* ARGSUSED */

View File

@@ -48,7 +48,7 @@ as GNU screen. Major features include:</p>
<li>A powerful, consistent, well-documented and easily scriptable command <li>A powerful, consistent, well-documented and easily scriptable command
interface.</li> interface.</li>
<li>A window may be split horizontally and vertically into panes.</li> <li>A window may be split horizontally and vertically into panes.</li>
<li>Panes can be freely moved and resized, or arranged into preset <li>Panes can be freely moved and resized, or arranged into one of four preset
layouts. </li> layouts. </li>
<li>Support for UTF-8 and 256-colour terminals.</li> <li>Support for UTF-8 and 256-colour terminals.</li>
<li>Copy and paste with multiple buffers.</li> <li>Copy and paste with multiple buffers.</li>

View File

@@ -1,4 +1,4 @@
/* $Id: xmalloc.c,v 1.13 2010-09-07 19:32:58 nicm Exp $ */ /* $Id: xmalloc.c,v 1.12 2009-10-28 23:12:38 tcunha Exp $ */
/* /*
* Copyright (c) 2004 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2004 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,6 +20,7 @@
#include <errno.h> #include <errno.h>
#include <libgen.h> #include <libgen.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@@ -1,4 +1,4 @@
/* $Id: xterm-keys.c,v 1.7 2010-10-24 00:30:51 tcunha Exp $ */ /* $Id: xterm-keys.c,v 1.5 2009-12-04 22:14:47 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -114,23 +114,27 @@ int
xterm_keys_modifiers(const char *template, const char *buf, size_t len) xterm_keys_modifiers(const char *template, const char *buf, size_t len)
{ {
size_t idx; size_t idx;
int param, modifiers;
idx = strcspn(template, "_"); idx = strcspn(template, "_");
if (idx >= len) if (idx >= len)
return (0); return (0);
param = buf[idx] - '1'; switch (buf[idx]) {
case '2':
modifiers = 0; return (KEYC_SHIFT);
if (param & 1) case '3':
modifiers |= KEYC_SHIFT; return (KEYC_ESCAPE);
if (param & 2) case '4':
modifiers |= KEYC_ESCAPE; return (KEYC_SHIFT|KEYC_ESCAPE);
if (param & 4) case '5':
modifiers |= KEYC_CTRL; return (KEYC_CTRL);
if (param & 8) case '6':
modifiers |= KEYC_ESCAPE; return (KEYC_SHIFT|KEYC_CTRL);
return (modifiers); case '7':
return (KEYC_ESCAPE|KEYC_CTRL);
case '8':
return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL);
}
return (0);
} }
/* /*
@@ -167,21 +171,30 @@ xterm_keys_lookup(int key)
int modifiers; int modifiers;
char *out; char *out;
modifiers = 1; #define KEY_MODIFIERS(key, modifiers) \
if (key & KEYC_SHIFT) (((key) & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) == (modifiers))
modifiers += 1; modifiers = 0;
if (key & KEYC_ESCAPE) if (KEY_MODIFIERS(key, KEYC_SHIFT))
modifiers += 2; modifiers = 2;
if (key & KEYC_CTRL) else if (KEY_MODIFIERS(key, KEYC_ESCAPE))
modifiers += 4; modifiers = 3;
if (key & KEYC_ESCAPE) else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE))
modifiers += 8; modifiers = 4;
else if (KEY_MODIFIERS(key, KEYC_CTRL))
modifiers = 5;
else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_CTRL))
modifiers = 6;
else if (KEY_MODIFIERS(key, KEYC_ESCAPE|KEYC_CTRL))
modifiers = 7;
else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL))
modifiers = 8;
#undef KEY_MODIFIERS
/* /*
* If the key has no modifiers, return NULL and let it fall through to * If the key has no modifiers, return NULL and let it fall through to
* the normal lookup. * the normal lookup.
*/ */
if (modifiers == 1) if (modifiers == 0)
return (NULL); return (NULL);
/* Otherwise, find the key in the table. */ /* Otherwise, find the key in the table. */