/* $OpenBSD$ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fnmatch.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>
#include <unistd.h>
#include "tmux.h"
static int cmd_find_session_better(struct session *, struct session *,
int);
static struct session *cmd_find_best_session(struct session **, u_int, int);
static int cmd_find_best_session_with_window(struct cmd_find_state *);
static int cmd_find_best_winlink_with_window(struct cmd_find_state *);
static const char *cmd_find_map_table(const char *[][2], const char *);
static int cmd_find_get_session(struct cmd_find_state *, const char *);
static int cmd_find_get_window(struct cmd_find_state *, const char *, int);
static int cmd_find_get_window_with_session(struct cmd_find_state *,
const char *);
static int cmd_find_get_pane(struct cmd_find_state *, const char *, int);
static int cmd_find_get_pane_with_session(struct cmd_find_state *,
const char *);
static int cmd_find_get_pane_with_window(struct cmd_find_state *,
const char *);
static const char *cmd_find_session_table[][2] = {
{ NULL, NULL }
};
static const char *cmd_find_window_table[][2] = {
{ "{start}", "^" },
{ "{last}", "!" },
{ "{end}", "$" },
{ "{next}", "+" },
{ "{previous}", "-" },
{ NULL, NULL }
};
static const char *cmd_find_pane_table[][2] = {
{ "{last}", "!" },
{ "{next}", "+" },
{ "{previous}", "-" },
{ "{top}", "top" },
{ "{bottom}", "bottom" },
{ "{left}", "left" },
{ "{right}", "right" },
{ "{top-left}", "top-left" },
{ "{top-right}", "top-right" },
{ "{bottom-left}", "bottom-left" },
{ "{bottom-right}", "bottom-right" },
{ "{up-of}", "{up-of}" },
{ "{down-of}", "{down-of}" },
{ "{left-of}", "{left-of}" },
{ "{right-of}", "{right-of}" },
{ NULL, NULL }
};
/* Get session from TMUX if present. */
static struct session *
cmd_find_try_TMUX(struct client *c)
{
struct environ_entry *envent;
char tmp[256];
long long pid;
u_int session;
envent = environ_find(c->environ, "TMUX");
if (envent == NULL)
return (NULL);
if (sscanf(envent->value, "%255[^,],%lld,%d", tmp, &pid, &session) != 3)
return (NULL);
if (pid != getpid())
return (NULL);
log_debug("client %p TMUX %s (session @%u)", c, envent->value, session);
return (session_find_by_id(session));
}
/* Find pane containing client if any. */
static struct window_pane *
cmd_find_inside_pane(struct client *c)
{
struct window_pane *wp;
if (c == NULL)
return (NULL);
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, c->ttyname) == 0)
break;
}
return (wp);
}
/* Is this client better? */
static int
cmd_find_client_better(struct client *c, struct client *than)
{
if (than == NULL)
return (1);
return (timercmp(&c->activity_time, &than->activity_time, >));
}
/* Find best client for session. */
struct client *
cmd_find_best_client(struct session *s)
{
struct client *c_loop, *c;
if (s->flags & SESSION_UNATTACHED)
s = NULL;
c = NULL;
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (s != NULL && c_loop->session != s)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
return (c);
}
/* Is this session better? */
static int
cmd_find_session_better(struct session *s, struct session *than
|