d4e63a2bd24c9b31a9a44e182a33978d787f8464 — Simon Ser 15 days ago 7c20ded
builtin/hash: new utility

This implements a minimal hash(1) utility, without any caching.
5 files changed, 57 insertions(+), 1 deletions(-)

M builtin/builtin.c
A builtin/hash.c
M configure
M include/builtin.h
M meson.build
M builtin/builtin.c => builtin/builtin.c +2 -1
@@ 28,6 28,7 @@ { "false", builtin_false, false },
  	{ "fg", builtin_fg, false },
  	{ "getopts", builtin_getopts, false },
+ 	{ "hash", builtin_hash, false },
  	{ "jobs", builtin_jobs, false },
  	{ "pwd", builtin_pwd, false },
  	{ "read", builtin_read, false },


@@ 69,7 70,7 @@   static int unspecified_compare(const void *_a, const void *_b) {
  	const char *a = _a;
- 	const char * const *b = _b;
+ 	const char *const *b = _b;
  	return strcmp(a, *b);
  }
  

A builtin/hash.c => builtin/hash.c +52 -0
@@ 0,0 1,52 @@
+ #include <mrsh/getopt.h>
+ #include <mrsh/builtin.h>
+ #include <shell/path.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include "builtin.h"
+ 
+ static const char hash_usage[] = "usage: hash -r|utility...\n";
+ 
+ int builtin_hash(struct mrsh_state *state, int argc, char *argv[]) {
+ 	/* Hashing and remembering executable location isn't implemented. Thus most
+ 	 * of this builtin just does nothing. */
+ 	mrsh_optind = 0;
+ 	int opt;
+ 	while ((opt = mrsh_getopt(argc, argv, ":r")) != -1) {
+ 		switch (opt) {
+ 		case 'r':
+ 			/* no-op: reset list of cached utilities */
+ 			return 0;
+ 		default:
+ 			fprintf(stderr, "hash: unknown option -- %c\n", mrsh_optopt);
+ 			fprintf(stderr, hash_usage);
+ 			return 1;
+ 		}
+ 	}
+ 
+ 	if (argc == 1) {
+ 		/* no-op: print list of cached utilities */
+ 		return 0;
+ 	}
+ 
+ 	for (int i = 1; i < argc; i++) {
+ 		const char *utility = argv[i];
+ 		if (strchr(utility, '/') != NULL) {
+ 			fprintf(stderr,
+ 				"hash: undefined behaviour: utility contains a slash\n");
+ 			return 1;
+ 		}
+ 
+ 		if (mrsh_has_builtin(utility)) {
+ 			continue;
+ 		}
+ 
+ 		const char *path = expand_path(state, utility, true);
+ 		if (path == NULL) {
+ 			fprintf(stderr, "hash: command not found: %s\n", utility);
+ 			return 1;
+ 		}
+ 	}
+ 
+ 	return 0;
+ }

M configure => configure +1 -0
@@ 47,6 47,7 @@ 'builtin/false.c' \
  		'builtin/fg.c' \
  		'builtin/getopts.c' \
+ 		'builtin/hash.c' \
  		'builtin/jobs.c' \
  		'builtin/pwd.c' \
  		'builtin/read.c' \

M include/builtin.h => include/builtin.h +1 -0
@@ 21,6 21,7 @@ int builtin_false(struct mrsh_state *state, int argc, char *argv[]);
  int builtin_fg(struct mrsh_state *state, int argc, char *argv[]);
  int builtin_getopts(struct mrsh_state *state, int argc, char *argv[]);
+ int builtin_hash(struct mrsh_state *state, int argc, char *argv[]);
  int builtin_jobs(struct mrsh_state *state, int argc, char *argv[]);
  int builtin_pwd(struct mrsh_state *state, int argc, char *argv[]);
  int builtin_read(struct mrsh_state *state, int argc, char *argv[]);

M meson.build => meson.build +1 -0
@@ 86,6 86,7 @@ 'builtin/false.c',
  		'builtin/fg.c',
  		'builtin/getopts.c',
+ 		'builtin/hash.c',
  		'builtin/jobs.c',
  		'builtin/pwd.c',
  		'builtin/read.c',