--- src/config.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++------ src/config.h | 2 +- src/mbsync.1 | 6 +++-- 3 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/src/config.c b/src/config.c index 456bd47..0cc0d31 100644 --- a/src/config.c +++ b/src/config.c @@ -25,11 +25,57 @@ char FieldDelimiter = ':'; DEF_BIT_FORMATTER_FUNCTION(ops, OP) char * -expand_strdup( const char *s, const conffile_t *cfile ) +expand_env_strdup( const char *s, conffile_t *cfile ) +{ + const char *e, *val; + char path[_POSIX_PATH_MAX]; + char *r = path; + while (*s) { + if (*s == '$') { + s++; + e = s; + if (isalpha( *s ) || *s == '_') { + while (*e && (isalnum( *e ) || *e == '_')) { + e++; + } + val = getenv( nfstrndup( s, e - s ) ); + } else if (*s == '{') { + s++; + e++; + while (*e && *e != '}') { + e++; + } + if (!*e || *e != '}') { + error( "%s:%d: unterminated variable expansion\n", cfile->file, cfile->line ); + cfile->err = 1; + } + e++; + val = getenv( nfstrndup( s, e - s - 1 ) ); + } else { + if (*s == '$') + e++; + val = "$"; + } + r += nfsnprintf( r, sizeof(path) - (r - path), "%s", val ); + s = e; + } else { + *r = *s; + r++; + s++; + } + if (r >= path + sizeof(path)) + oob(); + } + *r = 0; + return nfstrdup(path); +} + +char * +expand_strdup( const char *s, conffile_t *cfile ) { struct passwd *pw; const char *p, *q; - char *r; + char *r, *t; if (*s == '~') { s++; @@ -52,12 +98,15 @@ expand_strdup( const char *s, const conffile_t *cfile ) q = pw->pw_dir; } nfasprintf( &r, "%s%s", q, p ? p : "" ); - return r; - } else if (*s != '/') { - nfasprintf( &r, "%.*s%s", cfile->path_len, cfile->file, s ); - return r; + return expand_env_strdup( r, cfile ); } else { - return nfstrdup( s ); + r = expand_env_strdup( s, cfile ); + if (*r != '/') { + nfasprintf( &t, "%.*s%s", cfile->path_len, cfile->file, r ); + free( r ); + return t; + } + return r; } } diff --git a/src/config.h b/src/config.h index 0762b58..95c35aa 100644 --- a/src/config.h +++ b/src/config.h @@ -27,7 +27,7 @@ extern char FieldDelimiter; #define ARG_OPTIONAL 0 #define ARG_REQUIRED 1 -char *expand_strdup( const char *s, const conffile_t *cfile ); +char *expand_strdup( const char *s, conffile_t *cfile ); char *get_arg( conffile_t *cfile, int required, int *comment ); diff --git a/src/mbsync.1 b/src/mbsync.1 index 939c8c5..2161eef 100644 --- a/src/mbsync.1 +++ b/src/mbsync.1 @@ -126,8 +126,10 @@ Configuration items are keywords followed by one or more arguments; arguments containing spaces must be enclosed in double quotes (\fB"\fR), and literal double quotes and backslashes (\fB\\\fR) must be backslash-escaped. All keywords (including those used as arguments) are case-insensitive. -Bash-like home directory expansion using the tilde (\fB~\fR) is supported -in all options which represent local paths. +Bash-like home directory expansion using the tilde (\fB~\fR), and variable +expansion using both \fB$VAR\fR and \fB${VAR}\fR is supported in all +options which represent local paths. A literal \fB$\fR is represented +by doubling it. The reference point for relative local paths is the configuration file's containing directory. There are a few global options, the others apply to particular sections. -- 2.41.0 _______________________________________________ isync-devel mailing list isync-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/isync-devel