From: Michael D. Lowis Date: Mon, 24 Jul 2017 20:29:24 +0000 (-0400) Subject: Added tfetch command X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3f02cdfa5b254911266a23cde284475727e463ab;p=projs%2Ftide.git Added tfetch command --- diff --git a/.gitignore b/.gitignore index 576417b..604d147 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ pick tests/pick hl-cpp pty +tfetch diff --git a/Makefile b/Makefile index a641ab6..e48d882 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ INCS = -Iinc/ -BINS = tide pick xcpd hl-cpp +BINS = tide pick xcpd hl-cpp tfetch MAN1 = docs/tide.1 docs/pick.1 docs/picktag.1 docs/pickfile.1 LIBEDIT_OBJS = \ @@ -40,6 +40,7 @@ clean: install: all mkdir -p $(PREFIX)/bin cp -f tcmd $(PREFIX)/bin + cp -f tfetch $(PREFIX)/bin cp -f tide $(PREFIX)/bin cp -f tide-hl.rb $(PREFIX)/bin cp -f tide-fetch.rb $(PREFIX)/bin @@ -50,6 +51,7 @@ install: all uninstall: rm -f $(PREFIX)/bin/tcmd + rm -f $(PREFIX)/bin/tfetch rm -f $(PREFIX)/bin/tide rm -f $(PREFIX)/bin/tide-hl.rb rm -f $(PREFIX)/bin/tide-fetch.rb @@ -68,6 +70,7 @@ tide: tide.o libedit.a pick: pick.o libedit.a xcpd: xcpd.o libedit.a hl-cpp: hl-cpp.o libedit.a +tfetch: tfetch.o tests/libedit: tests/libedit.o tests/lib/buf.o tests/lib/utf8.o libedit.a tests/tide: tests/tide.o libedit.a tests/pick: tests/pick.o libedit.a diff --git a/tfetch.c b/tfetch.c new file mode 100644 index 0000000..bf56757 --- /dev/null +++ b/tfetch.c @@ -0,0 +1,216 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include + +#ifdef __MACH__ + #define OPENCMD "open" +#else + #define OPENCMD "xdg-open" +#endif + +typedef struct { + enum { + COMPLETE=0, MATCHES, IS, ISSET, ISDIR, ISFILE, + SET, UNSET, FINDFILE, EXEC, LAUNCH, CHECK + } type; + char* arg1; + char* arg2; +} Rule; + +char* Matches[10]; + +Rule* BuiltinRules[] = { + (Rule[]){ // Match URLS and open them with the browser + { ISSET, "BROWSER", NULL }, + { MATCHES, "data", "^(https?|ftp)://.*" }, + { LAUNCH, "$BROWSER $0", NULL }, + { COMPLETE, NULL, NULL } + }, + (Rule[]){ // Open files with addresses in the editor + { ISSET, "EDITOR", NULL }, + { MATCHES, "data", "^([^:]+):([0-9]+)" }, + { ISFILE, "$1", NULL }, + { LAUNCH, "$EDITOR $0", NULL }, + { COMPLETE, NULL, NULL } + }, + (Rule[]){ // If it's an existing text file, open it with editor + { ISSET, "EDITOR", NULL }, + { ISFILE, "$data", NULL }, + { CHECK, "file --mime '$file' | grep -q 'text/'", NULL }, + { LAUNCH, "$EDITOR '$file'", NULL }, + { COMPLETE, NULL, NULL } + }, + (Rule[]){ // If it's an existing directory, open it with system default + { ISDIR, "$data", NULL }, + { LAUNCH, OPENCMD " $data", NULL }, + { COMPLETE, NULL, NULL } + }, +}; + +/******************************************************************************/ + +char* getvar(char* val) { + if (strlen(val) == 1 && isdigit(*val)) + val = Matches[*val - '0']; + else + val = getenv(val); + return (val ? val : ""); +} + +char* eval(char* str) { + static bool inited = false; + static char* patt = "\\$([a-zA-Z0-9_]+)"; + static regex_t regex; + + if (!inited && (regcomp(®ex, patt, REG_EXTENDED) < 0)) { + perror("regcomp() :"); + exit(1); + } + + regmatch_t matches[2] = {0}; + if (regexec(®ex, str, nelem(matches), matches, 0) < 0) { + return str; + } else if (matches[1].rm_so > 0) { + char* var = strndup(str+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so); + char* val = getvar(var); + size_t sz = strlen(str) + strlen(val); + char* exp = calloc(1, sz); + strncat(exp, str, matches[0].rm_so); + strcat(exp, val); + strcat(exp, str + matches[0].rm_eo); + return eval(exp); + } else { + return str; + } +} + +/******************************************************************************/ + +bool complete(void) { + exit(0); + return false; +} + +bool matches(char* var, char* patt) { + regex_t regex = {0}; + regmatch_t matches[10] = {0}; + if (regcomp(®ex, patt, REG_EXTENDED) == 0) { + var = getvar(var); + memset(Matches, 0, sizeof(Matches)); + int err = regexec(®ex, var, nelem(matches), matches, 0); + for (int i = 0; i < 10 && matches[i].rm_so >= 0; i++) { + Matches[i] = strndup(var+matches[i].rm_so, matches[i].rm_eo-matches[i].rm_so); + } + return (err == 0); + } + return false; +} + +bool var_is(char* var, char* val) { + return (strcmp(getvar(var), eval(val)) == 0); +} + +bool var_isset(char* var) { + return (getenv(var) != NULL); +} + +bool var_isdir(char* var) { + struct stat st = {0}; + char* path = eval(var); + if ((stat(path, &st) < 0) && (errno == ENOENT)) { + return false; + } else if (S_ISDIR(st.st_mode)) { + setenv("file", var, 1); + return true; + } else { + return false; + } +} + +bool var_isfile(char* var) { + struct stat st = {0}; + char* path = eval(var); + if ((stat(eval(var), &st) < 0) && (errno == ENOENT)) { + return false; + } else if (!S_ISDIR(st.st_mode)) { + return true; + } else { + return false; + } +} + +bool var_set(char* var, char* val) { + return (setenv(var, eval(val), 1) == 0); +} + +bool var_unset(char* var) { + return (unsetenv(var) == 0); +} + +bool find_file(char* file) { + return false; +} + +bool exec(char* cmd) { + return false; +} + +bool launch(char* cmd) { + int pid = fork(); + if (pid > 0) { + return true; + } else if (pid == 0) { + char* shellcmd[] = { getvar("SHELL"), "-c", NULL, NULL }; + if (!shellcmd[0]) shellcmd[0] = "/bin/sh"; + shellcmd[2] = eval(cmd); + exit(execvp(shellcmd[0], shellcmd)); + } + return false; +} + +bool checkcmd(char* cmd) { + return false; +} + +bool apply_rule(Rule* rule) { + switch (rule->type) { + case COMPLETE: exit(0); + case MATCHES: return matches(rule->arg1, rule->arg2); + case IS: return var_is(rule->arg1, rule->arg2); + case ISSET: return var_isset(rule->arg1); + case ISDIR: return var_isdir(rule->arg1); + case ISFILE: return var_isfile(rule->arg1); + case SET: return var_set(rule->arg1, rule->arg2); + case UNSET: return var_unset(rule->arg1); + case FINDFILE: return find_file(rule->arg1); + case EXEC: return exec(rule->arg1); + case LAUNCH: return launch(rule->arg1); + case CHECK: return checkcmd(rule->arg1); + } + return false; +} + +/******************************************************************************/ + +void usage(char* pname) { + fprintf(stderr, "Usage: %s [ITEM]\n", pname); + exit(1); +} + +int main(int argc, char** argv) { + if (argc != 2) usage(argv[0]); + setenv("data", argv[1], 1); + for (int i = 0; i < nelem(BuiltinRules); i++) { + for (Rule* rule = BuiltinRules[i]; true; rule++) { + //printf("%d '%s' '%s'\n", rule->type, rule->arg1, rule->arg2); + if (!apply_rule(rule)) + break; + } + puts(""); + } + return 1; +}