[RFC PATCH] RFC: expand_tilde () for potential future path expansion

Subject: [RFC PATCH] RFC: expand_tilde () for potential future path expansion

Date: Sat, 14 May 2016 14:33:08 +0300

To: notmuch@notmuchmail.org

Cc: bijan@chokoufe.com, Tomi Ollila

From: Tomi Ollila


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


Thread: