Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions access.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* access.c -- access testing and path searching ($Revision: 1.2 $) */

#define REQUIRE_STAT 1
#define REQUIRE_PARAM 1

#include "es.h"
Expand Down Expand Up @@ -40,7 +39,7 @@ static Boolean ingroupset(gidset_t gid) {
return FALSE;
}

static int testperm(struct stat *stat, unsigned int perm) {
extern int testperm(struct stat *stat, unsigned int perm) {
unsigned int mask;
static gidset_t uid, gid;
static Boolean initialized = FALSE;
Expand Down
4 changes: 3 additions & 1 deletion es.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ extern void setnoexport(List *list);
extern void addtolist(void *arg, char *key, void *value);
extern List *listvars(Boolean internal);
extern List *varswithprefix(char *prefix);
extern List *fnswithprefix(char *prefix);

typedef struct Push Push;
extern Push *pushlist;
Expand All @@ -216,6 +217,7 @@ extern void printstatus(int pid, int status);

/* access.c */

extern int testperm(struct stat *stat, unsigned int perm);
extern char *checkexecutable(char *file);


Expand Down Expand Up @@ -283,7 +285,7 @@ extern void *erealloc(void *p, size_t n);
extern void efree(void *p);
extern void ewrite(int fd, const char *s, size_t n);
extern long eread(int fd, char *buf, size_t n);
extern Boolean isabsolute(char *path);
extern Boolean isabsolute(const char *path);
extern Boolean streq2(const char *s, const char *t1, const char *t2);


Expand Down
120 changes: 114 additions & 6 deletions input.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,9 +529,109 @@ static char *list_completion_function(const char *text, int state) {
return result;
}

char **builtin_completion(const char *text, int UNUSED start, int UNUSED end) {
char **matches = NULL;
enum st {
NORMAL,
START, /* start of a command */
PIPESTART, /* just after a '|' */
PIPESTARTBRACKET, /* the '|[' in 'a |[2] b' */
LT /* the '<' in '<=word' */
};

/* detect if we're currently at the start of a line. works ~90% well */
static Boolean cmdstart(int point) {
int i;
Boolean quote = FALSE;
enum st state = START;
for (i = 0; i < point; i++) {
char c = rl_line_buffer[i];
if (c == '\'') {
quote = !quote;
continue;
}
if (quote) continue;

switch (state) {
case PIPESTARTBRACKET:
if (c == ']')
state = START;
break;
case LT:
if (c == '=')
state = START;
else
state = NORMAL;
break;
case PIPESTART:
if (c == '[') {
state = PIPESTARTBRACKET;
break;
}
state = START; /* does this handle || correctly? */
/* fallthrough */
case START:
if (c == ' ' || c == '\t' || c == '\n' || c == '!')
continue;
/* fallthrough */
case NORMAL:
switch (c) {
case '&': case '{': case '`':
state = START;
break;
case '|':
state = PIPESTART;
break;
case '<':
state = LT;
break;
default:
/* fallthroughs make this useful */
state = NORMAL;
break;
}
}
}
return state == START || state == PIPESTART;
}

/* first-position completion. includes
* - built-ins: local let for fn %closure match
* - functions
* - if absolute (including home), absolute executable files
*/
static List *listexecutables(char *text) {
int i = 0;
char *s;
List *compl = NULL;
static char *builtins[] = {"local", "let", "for", "fn", "%closure", "match"};
for (i = 0; i < 6; i++)
if (strneq(text, builtins[i], strlen(text)))
compl = mklist(mkstr(builtins[i]), compl);

compl = append(fnswithprefix(text), compl);

if (isabsolute(text) || *text == '~') {
i = 0;
/* goofy hack :) */
while ((s = rl_filename_completion_function(text, i)) != NULL) {
struct stat st;
i = 1;
/* TODO: ~/foo doesn't stat(), so don't try */
if (*s != '~') {
if (stat(s, &st) == -1)
continue;
/* 1 == EXEC */
if (testperm(&st, 1) != 0)
continue;
}
/* TODO: recurse in directories? */
compl = mklist(mkstr(s), compl);
}
}
return compl;
}

char **builtin_completion(const char *text, int start, int UNUSED end) {
/* variable or primitive completion */
if (*text == '$') {
wordslistgen = varswithprefix;
complprefix = "$";
Expand All @@ -543,14 +643,22 @@ char **builtin_completion(const char *text, int UNUSED start, int UNUSED end) {
case '^': complprefix = "$^"; break;
case '#': complprefix = "$#"; break;
}
matches = rl_completion_matches(text, list_completion_function);
return rl_completion_matches(text, list_completion_function);
}

/* ~foo => username. ~foo/bar already gets completed as filename. */
if (!matches && *text == '~' && !strchr(text, '/'))
matches = rl_completion_matches(text, rl_username_completion_function);
if (*text == '~' && !strchr(text, '/'))
return rl_completion_matches(text, rl_username_completion_function);

/* first-word completion, which is ~special~ */
if (cmdstart(start)) {
wordslistgen = listexecutables;
complprefix = "";
rl_attempted_completion_over = 1;
return rl_completion_matches(text, list_completion_function);
}

return matches;
return NULL; /* fall back to normal filename completion */
}
#endif /* HAVE_READLINE */

Expand Down
2 changes: 0 additions & 2 deletions stdenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@
#include <sys/ioctl.h>
#endif

#if REQUIRE_STAT
#include <sys/stat.h>
#endif

#if REQUIRE_DIRENT
#if HAVE_DIRENT_H
Expand Down
2 changes: 1 addition & 1 deletion util.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extern void uerror(char *s) {
}

/* isabsolute -- test to see if pathname begins with "/", "./", or "../" */
extern Boolean isabsolute(char *path) {
extern Boolean isabsolute(const char *path) {
return path[0] == '/'
|| (path[0] == '.' && (path[1] == '/'
|| (path[1] == '.' && path[2] == '/')));
Expand Down
15 changes: 15 additions & 0 deletions var.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ static void listwithprefix(void *arg, char *key, void *value) {
addtolist(arg, key, value);
}

static void fnwithprefix(void *arg, char *key, void *value) {
if (strneq(key, "fn-", 3) &&
strneq(key + 3, list_prefix, strlen(list_prefix)))
addtolist(arg, key + 3, value);
}

/* listvars -- return a list of all the (dynamic) variables */
extern List *listvars(Boolean internal) {
Ref(List *, varlist, NULL);
Expand All @@ -365,6 +371,15 @@ extern List *listvars(Boolean internal) {
RefReturn(varlist);
}

/* fnswithprefix -- return a list of all the (dynamic) functions
* matching the given prefix */
extern List *fnswithprefix(char *prefix) {
Ref(List *, fnlist, NULL);
list_prefix = prefix;
dictforall(vars, fnwithprefix, &fnlist);
RefReturn(fnlist);
}

/* varswithprefix -- return a list of all the (dynamic) variables
* matching the given prefix */
extern List *varswithprefix(char *prefix) {
Expand Down