[PATCH] Add command -v builtin.

Details
Message ID
<KBL7SuLPnieCeg5GvfAY0J-nPw2_tz4l96vy4H7NEqlkLh5cOSLJvPQHK98esvQkeFXG766kfKtFrYWHuIoOUEVsCiyPCj1o571W3sc3GF8=@protonmail.com>
DKIM signature
pass
Download raw message
Patch: +117 -0
---

This add only the -v behaviour for now. I'd like to contribute again so
let me know anything wrong, indent style, big C mistakes or whatever.

 builtin/builtin.c |   1 +
 builtin/command.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++
 include/builtin.h |   1 +
 meson.build       |   1 +
 4 files changed, 117 insertions(+)
 create mode 100644 builtin/command.c

diff --git a/builtin/builtin.c b/builtin/builtin.c
index 0f0c563..20ed598 100644
--- a/builtin/builtin.c
+++ b/builtin/builtin.c
@@ -18,6 +18,7 @@ static const struct builtin builtins[] = {
 	{ ":", builtin_colon, true },
 	{ "alias", builtin_alias, false },
 	{ "cd", builtin_cd, false },
+	{ "command", builtin_command, false },
 	{ "eval", builtin_eval, true },
 	{ "exit", builtin_exit, true },
 	{ "export", builtin_export, true },
diff --git a/builtin/command.c b/builtin/command.c
new file mode 100644
index 0000000..ee77516
--- /dev/null
+++ b/builtin/command.c
@@ -0,0 +1,114 @@
+#define _POSIX_C_SOURCE 200809L
+#include <errno.h>
+#include <limits.h>
+#include <mrsh/getopt.h>
+#include <mrsh/shell.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "builtin.h"
+
+static const char command_usage[] = "usage: command [-v|-V|-p] command_name [argument...]\n";
+
+int builtin_command(struct mrsh_state *state, int argc, char *argv[]) {
+    const char *look_alias = NULL;
+    const char *look_fn = NULL;
+    const char *path = NULL;
+    const char *command_name;
+
+    mrsh_optind = 0;
+    int opt;
+    int len_command_name = 0;
+    int len_full_path = 0;
+    struct stat check_file;
+
+    while ((opt = mrsh_getopt(argc, argv, ":vVp")) != -1) {
+        switch (opt) {
+            case 'v':
+                // first alias, then function, then PATH
+                if(argc != 3) return 1;
+                command_name = argv[mrsh_optind];
+                len_command_name = strlen(command_name);
+
+                look_alias = mrsh_hashtable_get(&state->aliases,command_name);
+                if(look_alias != NULL){
+                    printf("%s\n",command_name);
+                    return 0;
+                }
+
+                look_fn = mrsh_hashtable_get(&state->functions,command_name);
+                if(look_fn != NULL){
+                    printf("%s\n",command_name);
+                    return 0;
+                }
+
+                const char *default_path = "/bin:/usr/bin";  
+                char *used_path;
+
+                path = mrsh_env_get(state, "PATH", NULL);
+
+                if(path == NULL) {
+                    fprintf(stderr, "command: $PATH doesn't exists, searching in /bin:/usr/bin\n");
+                    used_path = (char *)default_path;
+                }
+                else
+                {
+                    used_path = malloc(strlen(path));
+                    strncpy(used_path,path,strlen(path)+1);
+                }
+
+                char *full_path = NULL;
+                char *p = NULL;
+                for (;;used_path = NULL) {
+                    p = strtok(used_path,":");
+
+                    if (p == NULL)
+                        break;
+
+                    len_full_path = strlen(p) + 1 + len_command_name + 1;
+                    full_path = malloc(len_full_path);
+                    if(full_path == NULL)
+                    {
+                        fprintf(stderr,"PANIC out of memory\n");
+                        return 666;
+                    }
+
+                    strncpy(full_path,p,strlen(p)+1);
+                    strncat(full_path,"/",1);
+                    strncat(full_path,command_name,len_command_name);
+                    full_path[len_full_path] = '\0'; 
+
+                    if(lstat(full_path,&check_file) == 0)
+                    {
+                        if(check_file.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+                        {
+                            printf("%s\n",full_path);
+                            free(full_path);
+                            return 0;
+                        }
+                    }
+
+                    free(full_path);
+                    full_path = NULL;
+                }
+
+                return 0x42;
+
+            case 'V':
+                fprintf(stderr, "command: `-p` and no arg not yet implemented\n");
+                return 1;
+            case 'p': // use getconf or not ?
+                // not implemented
+                break;
+            default:
+                fprintf(stderr, "command: unknown option -- %c\n", mrsh_optopt);
+                fprintf(stderr, command_usage);
+                return 1;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/include/builtin.h b/include/builtin.h
index 8a848c8..491a739 100644
--- a/include/builtin.h
+++ b/include/builtin.h
@@ -10,6 +10,7 @@ void print_escaped(const char *value);
 
 int builtin_alias(struct mrsh_state *state, int argc, char *argv[]);
 int builtin_cd(struct mrsh_state *state, int argc, char *argv[]);
+int builtin_command(struct mrsh_state *state, int argc, char *argv[]);
 int builtin_colon(struct mrsh_state *state, int argc, char *argv[]);
 int builtin_dot(struct mrsh_state *state, int argc, char *argv[]);
 int builtin_eval(struct mrsh_state *state, int argc, char *argv[]);
diff --git a/meson.build b/meson.build
index 41494c4..84931fb 100644
--- a/meson.build
+++ b/meson.build
@@ -75,6 +75,7 @@ lib_mrsh = library(
 		'builtin/alias.c',
 		'builtin/builtin.c',
 		'builtin/cd.c',
+                'builtin/command.c',
 		'builtin/colon.c',
 		'builtin/dot.c',
 		'builtin/eval.c',
-- 
-- 
2.20.1