(Second Try: This time it should come from a mail adress of the mailing list) Woops. Now we did it twice. I have my implementation directly in notmuch-config.c which makes it harder to test and to reuse elsewhere (not sure that this is necessary though). I tested mine to work with ~ ~/ ~foo/.mail ~foo/ ~foo ~bar/.mail ~bar/ ~bar (where bar is not a user in my system but foo is) and all cases work fine. I send the patch and then we can discuss how to proceed. For me both versions look good enough though. On 16-05-14, Tomi Ollila wrote: > One implementation how to do this. Output of the "tests". > > $ sh expand-tilde.c > + exec gcc -std=c99 -Wall -Wstrict-prototypes -Winit-self -Wformat=2 -Wcast-align -Wpointer-arith -Wextra -Wwrite-strings -Wcast-qual -Wshadow -Wmissing-include-dirs -Wundef -Wbad-function-cast -Wlogical-op -Waggregate-return -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wvla -Woverlength-strings -Wpadded -O2 -o expand-tilde expand-tilde.c > $ > $ ./expand-tilde > > input '~', expanded '/home/too', rest '' > input '~root', expanded '/root', rest '' > > $ HOME=/a/b/c/ ./expand-tilde '~' '~'/ "~$USER" "~$USER/" '~'root '~'root/ '~none' '~none/' > > input '~', expanded '/a/b/c/', rest '' > input '~/', expanded '/a/b/c/', rest '/' > input '~too', expanded '/home/too', rest '' > input '~too/', expanded '/home/too', rest '/' > input '~root', expanded '/root', rest '' > input '~root/', expanded '/root', rest '/' > input '~none', expanded '(null)', rest '~none' > input '~none/', expanded '(null)', rest '~none/' > > $ HOME= ./expand-tilde '~' '~'/ "~$USER" "~$USER/" > > input '~', expanded '', rest '' > input '~/', expanded '', rest '/' > input '~too', expanded '/home/too', rest '' > input '~too/', expanded '/home/too', rest '/' > > $ ( unset HOME; ./expand-tilde '~' '~'/ "~$USER" "~$USER/" ) > > input '~', expanded '(null)', rest '~' > input '~/', expanded '(null)', rest '~/' > input '~too', expanded '/home/too', rest '' > input '~too/', expanded '/home/too', rest '/' > --- > util/expand-tilde.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 102 insertions(+) > create mode 100644 util/expand-tilde.c > > diff --git a/util/expand-tilde.c b/util/expand-tilde.c > new file mode 100644 > index 0000000..e3097e6 > --- /dev/null > +++ b/util/expand-tilde.c > @@ -0,0 +1,102 @@ > +#if 0 /* -*- mode: c; c-file-style: "stroustrup"; tab-width: 8; -*- > + set -eu; trg=`exec basename "$0" .c`; rm -f "$trg" > + WARN="-Wall -Wstrict-prototypes -Winit-self -Wformat=2" # -pedantic > + WARN="$WARN -Wcast-align -Wpointer-arith " # -Wfloat-equal #-Werror > + WARN="$WARN -Wextra -Wwrite-strings -Wcast-qual -Wshadow" # -Wconversion > + WARN="$WARN -Wmissing-include-dirs -Wundef -Wbad-function-cast -Wlogical-op" > + WARN="$WARN -Waggregate-return -Wold-style-definition" > + WARN="$WARN -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls" > + WARN="$WARN -Wnested-externs -Winline -Wvla -Woverlength-strings -Wpadded" > + case ${1-} in '') set x -O2; shift; esac > + #case ${1-} in '') set x -ggdb; shift; esac > + set -x; exec ${CC:-gcc} -std=c99 $WARN "$@" -o "$trg" "$0" > + exit $? > + */ > +#endif > +/* > + * $ expand-tilde.c $ > + * > + * Author: Tomi Ollila -- too ät iki piste fi > + * > + * Created: Sat 14 May 2016 13:10:35 EEST too > + * Last modified: Sat 14 May 2016 14:22:10 +0300 too > + * > + * *** Public Domain *** > + */ > + > +#include <stdlib.h> > +#include <sys/types.h> > +#include <pwd.h> > + > +/* USER_NAME_MAX_LENGTH is not usually defined (publicly in standard paths). */ > + > +#ifndef USER_NAME_MAX_LENGTH > +#define USER_NAME_MAX_LENGTH 32 > +#endif > + > +static // for -Wmissing-prototypes > +/* This is modeled after expand-file-name in emacs sources (fileio.c); > + * simplified and using constant buffer for user name. > + * neither emacs nor this implementation has restrictions in username chars > + * ...we may be looking forward for multibyte usernames... > + */ > +const char * expand_tilde(const char * path, const char ** rest) > +{ > + if (path == NULL || path[0] != '~') { > + *rest = path; > + return NULL; > + } > + > + if (path[1] == '/' || path[1] == '\0') { > + const char * home = getenv ("HOME"); > + *rest = home? path + 1: path; > + return home; > + } > + > + char username[USER_NAME_MAX_LENGTH + 1]; > + int namepos = 0; > + const char * pathp = path + 1; > + > + while (1) { > + username[namepos++] = pathp++[0]; > + if (pathp[0] == '/' || pathp[0] == '\0') > + break; > + if (namepos >= USER_NAME_MAX_LENGTH) { > + *rest = path; > + return NULL; > + } > + } > + username[namepos] = '\0'; > + > + struct passwd * pw = getpwnam (username); > + if (pw == NULL) { > + *rest = path; > + return NULL; > + } > + *rest = path + 1 + namepos; > + return pw->pw_dir; > + } > + > +#include <stdio.h> > + > +static void print_expanded(const char * path) > +{ > + const char * rest; > + const char * expanded = expand_tilde(path, &rest); > + printf("input '%s', expanded '%s', rest '%s'\n", > + path, expanded, rest); > +} > + > +int main(int argc, char * argv[]) > +{ > + printf("\n"); > + if (argc < 2) { > + print_expanded("~\0-- this something not to be seen in output --"); > + print_expanded("~root\0-- this something not to be seen in output --"); > + } else { > + for (int i = 1; i < argc; i++) > + print_expanded(argv[i]); > + } > + printf("\n"); > + return 0; > +} > -- > 2.8.2 >