summaryrefslogtreecommitdiff
path: root/.config/wmii-hg/rbar.h
diff options
context:
space:
mode:
Diffstat (limited to '.config/wmii-hg/rbar.h')
-rw-r--r--.config/wmii-hg/rbar.h193
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]);
+ }
+}