diff options
Diffstat (limited to '.config/wmii-hg/rbar.h')
-rw-r--r-- | .config/wmii-hg/rbar.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/.config/wmii-hg/rbar.h b/.config/wmii-hg/rbar.h new file mode 100644 index 0000000..843ac52 --- /dev/null +++ b/.config/wmii-hg/rbar.h @@ -0,0 +1,193 @@ +#define _GNU_SOURCE /* program_invocation_name */ +#include <assert.h> /* assert(3p) */ +#include <errno.h> /* program_invocation_name */ +#include <error.h> /* error(3gnu) */ +#include <fcntl.h> /* O_* flags to open(3p) */ +#include <glob.h> /* glob(3p), globfree(3p), GLOB_* */ +#include <signal.h> /* sigaction(3p) */ +#include <stdio.h> /* dprintf(3p) */ +#include <stdlib.h> /* exit(3p), malloc(3p) */ +#include <string.h> /* strcmp(3p), strlen(3p), strcpy(3p) */ +#include <sys/stat.h> /* open(3p) */ +#include <unistd.h> /* unlink(3p) */ + +/* Main *************************************************************/ + +struct impl { + int (*left_click)(void); + int (*middle_click)(void); + int (*right_click)(void); + int (*scroll_up)(void); + int (*scroll_down)(void); + int (*update)(const char *tag); +} impl; + +#define errusage(...) do { \ + error(6, 0, __VA_ARGS__); \ + usage(2); \ + exit(2); \ +} while(0) + +void usage(int fd) { + dprintf(fd, + "Usage: %1$s NN_LABEL\n" + " or: %1$s BTN_ID\n" + " or: %1$s -h\n", + program_invocation_name); +} + +void sigexit(int sig) { + error(0, 0, "Cought signal: %d", sig); + exit(0); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + errusage("exactly 1 argument expected, got %d", argc-1); + } + const char *arg = argv[1]; + + if (strcmp(arg, "-h") == 0) { + usage(1); + exit(0); + } + + struct sigaction sa = { 0 }; + sa.sa_handler = sigexit; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + if ('1' <= arg[0] && arg[0] <= '5' && arg[1] == '\0') { + int (*fn)(void) = NULL; + switch (arg[0]) { + case '1': fn = impl.left_click; break; + case '2': fn = impl.middle_click; break; + case '3': fn = impl.right_click; break; + case '4': fn = impl.scroll_up; break; + case '5': fn = impl.scroll_down; break; + } + char *xrd = getenv("XDG_RUNTIME_DIR"); + if (xrd == NULL || xrd[0] == '\0') { + error(6, 0, "XDG_RUNTIME_DIR isn't set"); + } + if (fn == NULL) { + exit(0); + } else { + exit(fn()); + } + } + + if ('0' <= arg[0] && arg[0] <= '9' && + '0' <= arg[1] && arg[1] <= '9' && + arg[2] == '_') { + char *xrd = getenv("XDG_RUNTIME_DIR"); + if (xrd == NULL || xrd[0] == '\0') { + error(6, 0, "XDG_RUNTIME_DIR isn't set"); + } + if (impl.update == NULL) { + exit(0); + } else { + exit(impl.update(arg)); + } + } + + errusage("invalid argument: %s", arg); +} + +/* Util *************************************************************/ + +#define RBAR_DIRGLOB "/wmii*/rbar" + +char *rbar_globescape(const char *lit) { + size_t len = 0; + for (const char *a = lit; *a != '\0'; a++) { + switch (*a) { + case '\\': case '*': case '?': case '[': + len++; /* fall through */ + default: + len++; + } + } + + char *glob = malloc(len+1); + if (!glob) + error(1, errno, "rbar_globescape: malloc"); + + // copy 'a' to 'b' + char *b = glob; + for (const char *a = lit; *a != '\0'; a++) { + switch (*a) { + case '\\': case '*': case '?': case '[': + *(b++) = '\\'; /* fall through */ + default: + *(b++) = *a; + } + } + *b = '\0'; + + return glob; +} + +/* returns 0 or GLOB_NOMATCH */ +int rbar_write(const char *filename, const char *msg) { + static const char *xrd = NULL; + static size_t xrdlen; + if (!xrd) { + xrd = rbar_globescape(getenv("XDG_RUNTIME_DIR")); + xrdlen = strlen(xrd); + } + + char *fullglob = alloca(xrdlen+(sizeof RBAR_DIRGLOB)); + strcpy(fullglob, xrd); + strcpy(&fullglob[xrdlen], RBAR_DIRGLOB); + + glob_t globbuf = { 0 }; + switch (glob(fullglob, GLOB_ONLYDIR|GLOB_NOSORT, NULL, &globbuf)) { + case GLOB_NOSPACE: + error(1, ENOMEM, "rbar_write"); assert(0); + case GLOB_ABORTED: + error(1, errno, "rbar_write: glob"); assert(0); + case GLOB_NOMATCH: + return GLOB_NOMATCH; + } + + const size_t filenamelen = strlen(filename); + const size_t msglen = strlen(msg); + for (size_t i = 0; i < globbuf.gl_pathc; i++) { + const char *dirname = globbuf.gl_pathv[i]; + const size_t dirnamelen = strlen(dirname); + char *fullname = alloca(dirnamelen+1+filenamelen+1); + strcpy(fullname, dirname); + fullname[dirnamelen] = '/'; + strcpy(&fullname[dirnamelen+1], filename); + + int fd = open(fullname, O_WRONLY|O_APPEND|O_CREAT, 0666); + if (fd < 0) + continue; + write(fd, msg, msglen); + } + return 0; +} + +void rbar_remove(const char *fileglob) { + static const char *xrd = NULL; + static size_t xrdlen; + if (!xrd) { + xrd = rbar_globescape(getenv("XDG_RUNTIME_DIR")); + xrdlen = strlen(xrd); + } + + char *fullglob = alloca(xrdlen+(sizeof RBAR_DIRGLOB)+strlen(fileglob)+1); + strcpy(fullglob, xrd); + strcpy(&fullglob[xrdlen], RBAR_DIRGLOB); + fullglob[xrdlen+(sizeof RBAR_DIRGLOB)-1] = '/'; + strcpy(&fullglob[xrdlen+(sizeof RBAR_DIRGLOB)], fileglob); + + glob_t globbuf = { 0 }; + if (glob(fullglob, GLOB_NOSORT, NULL, &globbuf) != 0) + return; + for (size_t i = 0; i < globbuf.gl_pathc; i++) { + unlink(globbuf.gl_pathv[i]); + } +} |