From ba597da72e8a548403f2a86cbe864f6f8c087397 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 25 Jul 2008 17:20:40 +0000 Subject: [PATCH] Environment variables in configuration file. --- CHANGES | 17 ++++- cfg.c | 6 +- cmd-command-prompt.c | 6 +- cmd-string.c | 149 +++++++++++++++++++++++++++++++++++++------ tmux.h | 4 +- 5 files changed, 155 insertions(+), 27 deletions(-) diff --git a/CHANGES b/CHANGES index 55082fb2..aa82a4bf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,18 @@ +25 July 2008 + +* Shell variables may now be defined and used in configuration file. Define + variables with: + + VAR=1 + + And use with: + + renamew ${VAR} + renamew "x${VAR}x" + + Also some other fixes to make, for example, "abc""abc" work similarly to + the shell. + 24 July 2008 * Finally lose inconsistently-used SCREEN_DEF* defines. @@ -621,4 +636,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.154 2008-07-24 21:42:40 nicm Exp $ +$Id: CHANGES,v 1.155 2008-07-25 17:20:40 nicm Exp $ diff --git a/cfg.c b/cfg.c index 8a6729e5..44f516b7 100644 --- a/cfg.c +++ b/cfg.c @@ -1,4 +1,4 @@ -/* $Id: cfg.c,v 1.12 2008-06-21 10:19:36 nicm Exp $ */ +/* $Id: cfg.c,v 1.13 2008-07-25 17:20:40 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -78,11 +78,13 @@ load_cfg(const char *path, char **cause) } n++; - if ((cmd = cmd_string_parse(buf, cause)) == NULL) { + if (cmd_string_parse(buf, &cmd, cause) != 0) { if (*cause == NULL) continue; goto error; } + if (cmd == NULL) + continue; cfg_cause = NULL; ctx.msgdata = NULL; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index c156002a..d0bc5d9e 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -1,4 +1,4 @@ -/* $Id: cmd-command-prompt.c,v 1.4 2008-06-25 20:43:13 nicm Exp $ */ +/* $Id: cmd-command-prompt.c,v 1.5 2008-07-25 17:20:40 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -72,7 +72,7 @@ cmd_command_prompt_callback(void *data, char *s) if (s == NULL) return; - if ((cmd = cmd_string_parse(s, &cause)) == NULL) { + if (cmd_string_parse(s, &cmd, &cause) != 0) { if (cause == NULL) return; *cause = toupper((u_char) *cause); @@ -80,6 +80,8 @@ cmd_command_prompt_callback(void *data, char *s) xfree(cause); return; } + if (cmd == NULL) + return; ctx.msgdata = NULL; ctx.cursession = c->session; diff --git a/cmd-string.c b/cmd-string.c index e28cef2d..d50a4b26 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -1,4 +1,4 @@ -/* $Id: cmd-string.c,v 1.3 2008-06-19 21:20:27 nicm Exp $ */ +/* $Id: cmd-string.c,v 1.4 2008-07-25 17:20:40 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -21,6 +21,7 @@ #include #include #include +#include #include "tmux.h" @@ -29,7 +30,9 @@ */ int cmd_string_getc(const char *, size_t *); +void cmd_string_ungetc(const char *, size_t *); char *cmd_string_string(const char *, size_t *, char, int); +char *cmd_string_variable(const char *, size_t *); int cmd_string_getc(const char *s, size_t *p) @@ -39,18 +42,34 @@ cmd_string_getc(const char *s, size_t *p) return (s[(*p)++]); } -/* - * Parse command string. Return command or NULL on error. If returning NULL, - * cause is error string, or NULL for empty command. - */ -struct cmd * -cmd_string_parse(const char *s, char **cause) +void +cmd_string_ungetc(unused const char *s, size_t *p) { - size_t p; - int ch, argc; - char **argv, *buf, *t; + (*p)--; +} + +/* + * Parse command string. Return -1 on error. If returning 1, cause is error + * string, or NULL for empty command. + */ +int +cmd_string_parse(const char *s, struct cmd **cmd, char **cause) +{ + size_t p; + int ch, argc, rval; + char **argv, *buf, *t, *u; size_t len; - struct cmd *cmd; + + if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL) + t = strchr(s, '\0'); + if ((u = strchr(s, '=')) != NULL && u < t) { + if (putenv(s) != NULL) { + xasprintf(cause, "assignment failed: %s", s); + return (-1); + } + *cmd = NULL; + return (0); + } argv = NULL; argc = 0; @@ -58,9 +77,10 @@ cmd_string_parse(const char *s, char **cause) buf = NULL; len = 0; - cmd = NULL; - *cause = NULL; + + *cmd = NULL; + rval = -1; p = 0; for (;;) { @@ -69,14 +89,23 @@ cmd_string_parse(const char *s, char **cause) case '\'': if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL) goto error; - argv = xrealloc(argv, argc + 1, sizeof *argv); - argv[argc++] = t; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); break; case '"': if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) goto error; - argv = xrealloc(argv, argc + 1, sizeof *argv); - argv[argc++] = t; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + break; + case '$': + if ((t = cmd_string_variable(s, &p)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); break; case '#': /* Comment: discard rest of line. */ @@ -102,7 +131,8 @@ cmd_string_parse(const char *s, char **cause) if (argc == 0) goto out; - cmd = cmd_parse(argc, argv, cause); + *cmd = cmd_parse(argc, argv, cause); + rval = 0; goto out; default: if (len >= SIZE_MAX - 2) @@ -126,14 +156,14 @@ out: if (argv != NULL) xfree(argv); - return (cmd); + return (rval); } char * cmd_string_string(const char *s, size_t *p, char endch, int esc) { int ch; - char *buf; + char *buf, *t; size_t len; buf = NULL; @@ -160,6 +190,15 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc) break; } break; + case '$': + if (!esc) + break; + if ((t = cmd_string_variable(s, p)) == NULL) + goto error; + buf = xrealloc(buf, 1, len + strlen(t) + 1); + strlcpy(buf + len, t, strlen(t) + 1); + len += strlen(t); + continue; } if (len >= SIZE_MAX - 2) @@ -177,3 +216,73 @@ error: xfree(buf); return (NULL); } + +char * +cmd_string_variable(const char *s, size_t *p) +{ + int ch, fch; + char *buf, *t; + size_t len; + +#define cmd_string_first(ch) ((ch) == '_' || \ + ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) +#define cmd_string_other(ch) ((ch) == '_' || \ + ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \ + ((ch) >= '0' && (ch) <= '9')) + + buf = NULL; + len = 0; + + fch = EOF; + switch (ch = cmd_string_getc(s, p)) { + case EOF: + goto error; + case '{': + fch = '{'; + + ch = cmd_string_getc(s, p); + if (!cmd_string_first(ch)) + goto error; + /* FALLTHROUGH */ + default: + if (!cmd_string_first(ch)) { + xasprintf(&t, "$%c", ch); + return (t); + } + + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + + for(;;) { + ch = cmd_string_getc(s, p); + if (ch == EOF || !cmd_string_other(ch)) + break; + else { + if (len >= SIZE_MAX - 3) + goto error; + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + } + } + } + + if (fch == '{' && ch != '}') + goto error; + if (ch != EOF && fch != '{') + cmd_string_ungetc(s, p); /* ch */ + + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + + if ((t = getenv(buf)) == NULL) { + xfree(buf); + return (xstrdup("")); + } + xfree(buf); + return (xstrdup(t)); + +error: + if (buf != NULL) + xfree(buf); + return (NULL); +} diff --git a/tmux.h b/tmux.h index fa5edde6..40a68c4f 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.178 2008-07-24 22:21:28 nicm Exp $ */ +/* $Id: tmux.h,v 1.179 2008-07-25 17:20:40 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1025,7 +1025,7 @@ extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unlink_window_entry; /* cmd-string.c */ -struct cmd *cmd_string_parse(const char *, char **); +int cmd_string_parse(const char *, struct cmd **, char **); /* cmd-generic.c */ #define CMD_TARGET_WINDOW_USAGE "[-t target-window]"