diff options
Diffstat (limited to '.config/wmii-hg')
-rw-r--r-- | .config/wmii-hg/Makefile | 5 | ||||
-rw-r--r-- | .config/wmii-hg/rbar.h | 193 | ||||
-rw-r--r-- | .config/wmii-hg/rbar_clock.c | 56 | ||||
-rw-r--r-- | .config/wmii-hg/rbar_clock.go | 29 | ||||
-rw-r--r-- | .config/wmii-hg/rbar_util/main.go | 76 | ||||
-rw-r--r-- | .config/wmii-hg/rbar_util/util.go | 49 |
6 files changed, 251 insertions, 157 deletions
diff --git a/.config/wmii-hg/Makefile b/.config/wmii-hg/Makefile index 4ba64a3..85c1ab1 100644 --- a/.config/wmii-hg/Makefile +++ b/.config/wmii-hg/Makefile @@ -1,10 +1,9 @@ all: rbar_clock .PHONY: all -%: %.go - go build -o $@ $< +CFLAGS += -std=c99 -Wall -Werror -Wextra -rbar_clock: rbar_util $(wildcard rbar_util/*) +rbar_clock: rbar.h .SECONDARY: .DELETE_ON_ERROR: 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]); + } +} diff --git a/.config/wmii-hg/rbar_clock.c b/.config/wmii-hg/rbar_clock.c new file mode 100644 index 0000000..ab636c2 --- /dev/null +++ b/.config/wmii-hg/rbar_clock.c @@ -0,0 +1,56 @@ +#include "rbar.h" + +#include <stdint.h> /* uint64_t */ +#include <stdlib.h> /* atexit(3p) */ +#include <sys/timerfd.h> +#include <time.h> /* glock_gettime, localtime, strftime */ + +const char *cleanup_id; + +void cleanup(void) { + rbar_remove(rbar_globescape(cleanup_id)); +} + +int update(const char *id) { + cleanup_id = id; + atexit(cleanup); + + int timer = timerfd_create(CLOCK_REALTIME, 0); + if (timer < 0) + error(1, errno, "timerfd_create"); + + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + error(1, errno, "clock_gettime"); + + struct itimerspec spec = { + .it_interval = (struct timespec){.tv_sec = 1, .tv_nsec = 0}, + .it_value = (struct timespec){.tv_sec = now.tv_sec+1, .tv_nsec = 0}, + }; + + if (timerfd_settime(timer, TFD_TIMER_ABSTIME, &spec, NULL) < 0) + error(1, errno, "timerfd_settime"); + + for (;;) { + uint64_t count; + if (read(timer, &count, sizeof count) != sizeof count) + error(1, errno, "read"); + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + error(1, errno, "clock_gettime"); + char str[80]; + if (strftime(str, sizeof str, + "label %a %F %T %Z(%z)", /* apparently %:::z" is supported by date(1gnu) but not strftime(3gnu) */ + localtime(&now.tv_sec)) <= 0) + error(1, 0, "strftime wanted a really long string"); + int err = rbar_write(id, str); + if (err != 0) { + if (err == GLOB_NOMATCH) + return 0; + return 1; + } + } +} + +struct impl impl = { + .update = update, +}; diff --git a/.config/wmii-hg/rbar_clock.go b/.config/wmii-hg/rbar_clock.go deleted file mode 100644 index 247dd3a..0000000 --- a/.config/wmii-hg/rbar_clock.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "time" - - "./rbar_util" -) - -func main() { - rbar_util.Main(rbar_util.Impl{ - Update: func(id string) error { - defer rbar_util.Remove(rbar_util.GlobEscape(id)) - - now := time.Now() - start := now.Truncate(time.Second).Add(time.Second) - time.Sleep(start.Sub(now)) - - clock := time.NewTicker(1*time.Second) - defer clock.Stop() - for now := range clock.C { - err := rbar_util.Write(id, now.Format("label Mon 2006-01-02 15:04:05 MST(-07)")) - if err != nil { - return err - } - } - panic("not reached") - }, - }) -} diff --git a/.config/wmii-hg/rbar_util/main.go b/.config/wmii-hg/rbar_util/main.go deleted file mode 100644 index 2358dca..0000000 --- a/.config/wmii-hg/rbar_util/main.go +++ /dev/null @@ -1,76 +0,0 @@ -package rbar_util - -import ( - "os" - "io" - "fmt" -) - - -type Impl struct { - LeftClick func() error - MiddleClick func() error - RightClick func() error - ScrollUp func() error - ScrollDown func() error - Update func(tag string) error -} - -func gerror(status int, err error, format string, a ...interface{}) { - msg := fmt.Sprintf(format, a...) - if err == nil { - fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], msg) - } else { - fmt.Fprintf(os.Stderr, "%s: %s: %v", os.Args[0], msg, err) - } - if status != 0 { - os.Exit(status) - } -} - -func errusage(fmt string, a ...interface{}) { - gerror(0, nil, fmt, a...) - usage(os.Stderr) - os.Exit(2) -} - -func usage(w io.Writer) { - fmt.Fprintf(w, "Usage: %[1]v NN_LABEL\n or: %[1]v BTN_ID\n or: %[1]v -h\n", os.Args[0]) -} - -func Main(impl Impl) { - if len(os.Args) != 2 { - errusage("exactly 1 argument expected, got %d", len(os.Args)-1) - } - var fn func() error - switch os.Args[1] { - case "-h": - usage(os.Stdout) - os.Exit(0) - case "1": fn = impl.LeftClick; - case "2": fn = impl.MiddleClick; - case "3": fn = impl.RightClick; - case "4": fn = impl.ScrollUp; - case "5": fn = impl.ScrollDown; - default: - arg := os.Args[1] - if len(arg) > 3 && '0' <= arg[0] && arg[0] <= '9' && '0' <= arg[1] && arg[1] <= '9' && arg[2] == '_' { - if impl.Update != nil { - fn = func() error { return impl.Update(arg) } - } - } else { - errusage("invalid argument: %s", os.Args[1]) - } - } - if fn == nil { - fn = func() error { return nil } - } - if os.Getenv("XDG_RUNTIME_DIR") == "" { - gerror(6, nil, "XDG_RUNTIME_DIR isn't set") - } - err := fn() - if err != nil && err != NoRbar{ - gerror(1, err, "") - } - os.Exit(0) -} diff --git a/.config/wmii-hg/rbar_util/util.go b/.config/wmii-hg/rbar_util/util.go deleted file mode 100644 index 9e5d622..0000000 --- a/.config/wmii-hg/rbar_util/util.go +++ /dev/null @@ -1,49 +0,0 @@ -package rbar_util - -import ( - "os" - "io" - "path/filepath" - "strings" - "errors" - - "fmt" -) - -func GlobEscape(lit string) string { - glob := lit - glob = strings.Replace(glob, "\\", "\\\\", -1) - glob = strings.Replace(glob, "*", "\\*", -1) - glob = strings.Replace(glob, "?", "\\?", -1) - glob = strings.Replace(glob, "[", "\\[", -1) - return glob -} - -var NoRbar = errors.New("no WMII rbars found") - -func Write(filename string, msg string) error { - dirnames, _ := filepath.Glob(GlobEscape(os.Getenv("XDG_RUNTIME_DIR"))+"/wmii*/rbar") - if len(dirnames) == 0 { - return NoRbar - } - for _, dirname := range dirnames { - file, err := os.OpenFile(filepath.Join(dirname, filename), os.O_WRONLY| os.O_APPEND|os.O_CREATE, 0666) - if err != nil { - continue - } - io.WriteString(file, msg) - file.Close() - } - return nil -} - -func Remove(glob string) { - fmt.Println("remove", glob); - fullglob := GlobEscape(os.Getenv("XDG_RUNTIME_DIR"))+"/wmii*/rbar/"+glob - fmt.Println("glob", fullglob) - filenames, err := filepath.Glob(fullglob) - fmt.Println("globerr", err) - for _, filename := range filenames { - os.Remove(filename) - } -} |