[BACK]Return to cmd.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Diff for /src/usr.bin/tmux/cmd.c between version 1.4 and 1.5

version 1.4, 2009/07/09 15:47:49 version 1.5, 2009/07/13 17:47:46
Line 19 
Line 19 
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/time.h>  #include <sys/time.h>
   
   #include <fnmatch.h>
   #include <paths.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
Line 100 
Line 102 
         NULL          NULL
 };  };
   
   struct session  *cmd_newest_session(void);
   struct client   *cmd_lookup_client(const char *);
   struct session  *cmd_lookup_session(const char *, int *);
   struct winlink  *cmd_lookup_window(struct session *, const char *, int *);
   
 struct cmd *  struct cmd *
 cmd_parse(int argc, char **argv, char **cause)  cmd_parse(int argc, char **argv, char **cause)
 {  {
Line 294 
Line 301 
         return (s);          return (s);
 }  }
   
   /*
    * Figure out the current session. Use: 1) the current session, if the command
    * context has one; 2) the session specified in the TMUX variable from the
    * environment (as passed from the client); 3) the newest session.
    */
 struct session *  struct session *
 cmd_current_session(struct cmd_ctx *ctx)  cmd_current_session(struct cmd_ctx *ctx)
 {  {
         struct msg_command_data *data = ctx->msgdata;          struct msg_command_data *data = ctx->msgdata;
         struct timeval          *tv;          struct session          *s;
         struct session          *s, *newest = NULL;  
         u_int                    i;  
   
         if (ctx->cursession != NULL)          if (ctx->cursession != NULL)
                 return (ctx->cursession);                  return (ctx->cursession);
   
         if (data != NULL && data->pid != -1) {          if (data != NULL && data->pid != -1) {
                 if (data->pid != getpid()) {                  if (data->pid != getpid())
                         ctx->error(ctx, "wrong server: %ld", (long) data->pid);  
                         return (NULL);                          return (NULL);
                 }                  if (data->idx > ARRAY_LENGTH(&sessions))
                 if (data->idx > ARRAY_LENGTH(&sessions)) {  
                         ctx->error(ctx, "index out of range: %d", data->idx);  
                         return (NULL);                          return (NULL);
                 }                  if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
                 if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) {  
                         ctx->error(ctx, "session doesn't exist: %u", data->idx);  
                         return (NULL);                          return (NULL);
                 }  
                 return (s);                  return (s);
         }          }
   
         tv = NULL;          return (cmd_newest_session());
   }
   
   /* Find the newest session. */
   struct session *
   cmd_newest_session(void)
   {
           struct session  *s, *snewest;
           struct timeval  *tv = NULL;
           u_int            i;
   
           snewest = NULL;
         for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {          for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
                 s = ARRAY_ITEM(&sessions, i);                  if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
                 if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) {                          continue;
                         newest = ARRAY_ITEM(&sessions, i);  
                   if (tv == NULL || timercmp(&s->tv, tv, >)) {
                           snewest = s;
                         tv = &s->tv;                          tv = &s->tv;
                 }                  }
         }          }
         return (newest);  
           return (snewest);
 }  }
   
   /* Find the target client or report an error and return NULL. */
 struct client *  struct client *
 cmd_find_client(struct cmd_ctx *ctx, const char *arg)  cmd_find_client(struct cmd_ctx *ctx, const char *arg)
 {  {
         struct client   *c;          struct client   *c;
           char            *tmparg;
           size_t           arglen;
   
           /* A NULL argument means the current client. */
         if (arg == NULL)          if (arg == NULL)
                 c = ctx->curclient;                  return (ctx->curclient);
         else {          tmparg = xstrdup(arg);
                 if ((c = arg_parse_client(arg)) == NULL) {  
                         if (arg != NULL)          /* Trim a single trailing colon if any. */
                                 ctx->error(ctx, "client not found: %s", arg);          arglen = strlen(tmparg);
                         else          if (arglen != 0 && tmparg[arglen - 1] == ':')
                                 ctx->error(ctx, "no client found");                  tmparg[arglen - 1] = '\0';
   
           /* Find the client, if any. */
           c = cmd_lookup_client(tmparg);
   
           /* If no client found, report an error. */
           if (c == NULL)
                   ctx->error(ctx, "client not found: %s", tmparg);
   
           xfree(tmparg);
           return (c);
   }
   
   /*
    * Lookup a client by device path. Either of a full match and a match without a
    * leading _PATH_DEV ("/dev/") is accepted.
    */
   struct client *
   cmd_lookup_client(const char *name)
   {
           struct client   *c;
           const char      *path;
           u_int            i;
   
           for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
                   if ((c = ARRAY_ITEM(&clients, i)) == NULL)
                           continue;
                   path = c->tty.path;
   
                   /* Check for exact matches. */
                   if (strcmp(name, path) == 0)
                           return (c);
   
                   /* Check without leading /dev if present. */
                   if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
                           continue;
                   if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0)
                           return (c);
           }
   
           return (NULL);
   }
   
   /* Lookup a session by name. If no session is found, NULL is returned. */
   struct session *
   cmd_lookup_session(const char *name, int *ambiguous)
   {
           struct session  *s, *sfound;
           u_int            i;
   
           *ambiguous = 0;
   
           /*
            * Look for matches. Session names must be unique so an exact match
            * can't be ambigious and can just be returned.
            */
           sfound = NULL;
           for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
                   if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
                           continue;
   
                   /* Check for an exact match and return it if found. */
                   if (strcmp(name, s->name) == 0)
                           return (s);
   
                   /* Then check for pattern matches. */
                   if (strncmp(name, s->name, strlen(name)) == 0 ||
                       fnmatch(name, s->name, 0) == 0) {
                           if (sfound != NULL) {
                                   *ambiguous = 1;
                                   return (NULL);
                           }
                           sfound = s;
                 }                  }
         }          }
         return (c);  
           return (sfound);
 }  }
   
   /*
    * Lookup a window or return -1 if not found or ambigious. First try as an index
    * and if invalid, use fnmatch or leading prefix.
    */
   struct winlink *
   cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
   {
           struct winlink  *wl, *wlfound;
           struct window   *w;
           const char      *errstr;
           u_int            idx;
   
           *ambiguous = 0;
   
           /* First see if this is a valid window index in this session. */
           idx = strtonum(name, 0, INT_MAX, &errstr);
           if (errstr == NULL) {
                   if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL)
                           return (wl);
           }
   
           /* Look for exact matches, error if more than one. */
           wlfound = NULL;
           RB_FOREACH(wl, winlinks, &s->windows) {
                   w = wl->window;
                   if (strcmp(name, w->name) == 0) {
                           if (wlfound != NULL) {
                                   *ambiguous = 1;
                                   return (NULL);
                           }
                           wlfound = wl;
                   }
           }
           if (wlfound != NULL)
                   return (wlfound);
   
           /* Now look for pattern matches, again error if multiple. */
           wlfound = NULL;
           RB_FOREACH(wl, winlinks, &s->windows) {
                   w = wl->window;
                   if (strncmp(name, w->name, strlen(name)) == 0 ||
                       fnmatch(name, w->name, 0) == 0) {
                           if (wlfound != NULL) {
                                   *ambiguous = 1;
                                   return (NULL);
                           }
                           wlfound = wl;
                   }
           }
           if (wlfound != NULL)
                   return (wlfound);
   
           return (NULL);
   }
   
   /* Find the target session or report an error and return NULL. */
 struct session *  struct session *
 cmd_find_session(struct cmd_ctx *ctx, const char *arg)  cmd_find_session(struct cmd_ctx *ctx, const char *arg)
 {  {
         struct session  *s;          struct session  *s;
           struct client   *c;
           char            *tmparg;
           size_t           arglen;
           int              ambiguous;
   
           /* A NULL argument means the current session. */
         if (arg == NULL)          if (arg == NULL)
                 s = cmd_current_session(ctx);                  return (cmd_current_session(ctx));
         else {          tmparg = xstrdup(arg);
                 if ((s = arg_parse_session(arg)) == NULL) {  
                         if (arg != NULL)          /* Trim a single trailing colon if any. */
                                 ctx->error(ctx, "session not found: %s", arg);          arglen = strlen(tmparg);
                         else          if (arglen != 0 && tmparg[arglen - 1] == ':')
                                 ctx->error(ctx, "no session found");                  tmparg[arglen - 1] = '\0';
                 }  
           /* Find the session, if any. */
           s = cmd_lookup_session(tmparg, &ambiguous);
   
           /* If it doesn't, try to match it as a client. */
           if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
                   s = c->session;
   
           /* If no session found, report an error. */
           if (s == NULL) {
                   if (ambiguous)
                           ctx->error(ctx, "more than one session: %s", tmparg);
                   else
                           ctx->error(ctx, "session not found: %s", tmparg);
         }          }
   
           xfree(tmparg);
         return (s);          return (s);
 }  }
   
   /* Find the target session and window or report an error and return NULL. */
 struct winlink *  struct winlink *
 cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)  cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
 {  {
         struct session  *s;          struct session  *s;
         struct winlink  *wl;          struct winlink  *wl;
         int              idx;          const char      *winptr;
           char            *sessptr = NULL;
           int              ambiguous = 0;
   
         wl = NULL;          /*
         if (arg_parse_window(arg, &s, &idx) != 0) {           * Find the current session. There must always be a current session, if
                 ctx->error(ctx, "bad window: %s", arg);           * it can't be found, report an error.
            */
           if ((s = cmd_current_session(ctx)) == NULL) {
                   ctx->error(ctx, "can't establish current session");
                 return (NULL);                  return (NULL);
         }          }
         if (s == NULL)  
                 s = ctx->cursession;          /* A NULL argument means the current session and window. */
         if (s == NULL)          if (arg == NULL) {
                 s = cmd_current_session(ctx);                  if (sp != NULL)
         if (s == NULL)                          *sp = s;
                 return (NULL);                  return (s->curw);
           }
   
           /* Time to look at the argument. If it is empty, that is an error. */
           if (*arg == '\0')
                   goto not_found;
   
           /* Find the separating colon. If none, assume the current session. */
           winptr = strchr(arg, ':');
           if (winptr == NULL)
                   winptr = xstrdup(arg);
           else {
                   winptr++;       /* skip : */
                   sessptr = xstrdup(arg);
                   *strchr(sessptr, ':') = '\0';
           }
   
           log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
   
           /* Try to lookup the session if present. */
           if (sessptr != NULL && *sessptr != '\0') {
                   if  ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
                           goto no_session;
           }
         if (sp != NULL)          if (sp != NULL)
                 *sp = s;                  *sp = s;
   
         if (idx == -1)          /*
            * Then work out the window. An empty string is the current window,
            * otherwise try to look it up in the session.
            */
           if (winptr == NULL || *winptr == '\0')
                 wl = s->curw;                  wl = s->curw;
         else          else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL)
                 wl = winlink_find_by_index(&s->windows, idx);                  goto not_found;
         if (wl == NULL)  
                 ctx->error(ctx, "window not found: %s:%d", s->name, idx);          if (sessptr != NULL)
                   xfree(sessptr);
         return (wl);          return (wl);
   
   no_session:
           if (ambiguous)
                   ctx->error(ctx, "multiple sessions: %s", sessptr);
           else
                   ctx->error(ctx, "session not found: %s", sessptr);
           if (sessptr != NULL)
                   xfree(sessptr);
           return (NULL);
   
   not_found:
           if (ambiguous)
                   ctx->error(ctx, "multiple windows: %s", arg);
           else
                   ctx->error(ctx, "window not found: %s", arg);
           if (sessptr != NULL)
                   xfree(sessptr);
           return (NULL);
   }
   
   /*
    * Find the target session and window index, whether or not it exists in the
    * session. Return -2 on error or -1 if no window index is specified. This is
    * used when parsing an argument for a window target that may not be exist (for
    * example it is going to be created).
    */
   int
   cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
   {
           struct session  *s;
           struct winlink  *wl;
           const char      *winptr, *errstr;
           char            *sessptr = NULL;
           int              idx, ambiguous = 0;
   
           /*
            * Find the current session. There must always be a current session, if
            * it can't be found, report an error.
            */
           if ((s = cmd_current_session(ctx)) == NULL) {
                   ctx->error(ctx, "can't establish current session");
                   return (NULL);
           }
   
           /* A NULL argument means the current session and "no window" (-1). */
           if (arg == NULL) {
                   if (sp != NULL)
                           *sp = s;
                   return (-1);
           }
   
           /* Time to look at the argument. If it is empty, that is an error. */
           if (*arg == '\0')
                   goto not_found;
   
           /* Find the separating colon. If none, assume the current session. */
           winptr = strchr(arg, ':');
           if (winptr == NULL)
                   winptr = xstrdup(arg);
           else {
                   winptr++;       /* skip : */
                   sessptr = xstrdup(arg);
                   *strchr(sessptr, ':') = '\0';
           }
   
           log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
   
           /* Try to lookup the session if present. */
           if (sessptr != NULL && *sessptr != '\0') {
                   if  ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
                           goto no_session;
           }
           if (sp != NULL)
                   *sp = s;
   
           /*
            * Then work out the window. No : means "no window" (-1), an empty
            * string is the current window, otherwise try to look it up in the
            * session.
            */
           if (winptr == NULL)
                   idx = -1;
           else if (*winptr == '\0')
                   idx = s->curw->idx;
           else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) {
                   if (ambiguous)
                           goto not_found;
                   /* Don't care it doesn't exist if this is a valid index. */
                   idx = strtonum(winptr, 0, INT_MAX, &errstr);
                   if (errstr != NULL)  {
                           ctx->error(ctx, "index %s: %s", errstr, winptr);
                           idx = -2;
                   }
           } else
                   idx = wl->idx;
   
           if (sessptr != NULL)
                   xfree(sessptr);
           return (idx);
   
   no_session:
           if (ambiguous)
                   ctx->error(ctx, "multiple sessions: %s", sessptr);
           else
                   ctx->error(ctx, "session not found: %s", sessptr);
           if (sessptr != NULL)
                   xfree(sessptr);
           return (-2);
   
   not_found:
           if (ambiguous)
                   ctx->error(ctx, "multiple windows: %s", arg);
           else
                   ctx->error(ctx, "window not found: %s", arg);
           if (sessptr != NULL)
                   xfree(sessptr);
           return (-2);
 }  }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5