summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2018-01-29 13:37:52 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2018-03-21 14:13:05 -0400
commit7bf7d5aa5c1df452fd88f26026f129fd9b49fbe1 (patch)
treeb5314b4ef2c470e169d6dec9415f2b32f63b7403
parentaffee5f76f0cd83ec28179b30456f311b82ea450 (diff)
wmii: rbar_clock: re-implement in C
-rw-r--r--.config/wmii-hg/Makefile5
-rw-r--r--.config/wmii-hg/rbar.h193
-rw-r--r--.config/wmii-hg/rbar_clock.c56
-rw-r--r--.config/wmii-hg/rbar_clock.go29
-rw-r--r--.config/wmii-hg/rbar_util/main.go76
-rw-r--r--.config/wmii-hg/rbar_util/util.go49
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)
- }
-}