diff options
author | Thomas Voss <mail@thomasvoss.com> | 2022-10-12 21:12:03 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2022-10-12 21:12:03 +0200 |
commit | 134c79f3d65928c18826f5ca2aae23130ed038cd (patch) | |
tree | b1de0603e0a97858d0dea0f41948ec3f0b935576 | |
parent | 4563949de32e17ab26e4f7d6307cd7521cedfcf9 (diff) |
Prepare the switch to Go
-rw-r--r-- | mstatus.1 | 130 | ||||
-rw-r--r-- | mstatus.c | 318 |
2 files changed, 0 insertions, 448 deletions
diff --git a/mstatus.1 b/mstatus.1 deleted file mode 100644 index 672dba1..0000000 --- a/mstatus.1 +++ /dev/null @@ -1,130 +0,0 @@ -.\" vi: tw=80 -.\" -.\" BSD Zero Clause License -.\" -.\" Copyright (c) 2022 Thomas Voss -.\" -.\" Permission to use, copy, modify, and/or distribute this software for any -.\" purpose with or without fee is hereby granted. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -.\" AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -.\" OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -.\" PERFORMANCE OF THIS SOFTWARE. -.Dd $Mdocdate: September 23 2022 $ -.Dt MSTATUS 1 -.Os -.Sh NAME -.Nm mstatus -.Nd a modular status bar -.Sh SYNOPSIS -.Nm -.Op Fl r -.Op Fl s Ar seperator -.Sh DESCRIPTION -.Nm -is a modular status bar. -The -.Nm -status bar is comprised of a series of blocks which can be programmatically -added, removed, and updated. -These blocks appear side by side on the status bar seperated by the string -.Dq " | " , -although this can be configured with the -.Fl s -flag. -Commands are sent to and from the status bar via a named pipe located at -.Pa $XDG_RUNTIME_DIR/mstatus.pipe -or -.Pa /run/user/$(id -u)/mstatus.pipe -if the -.Ev $XDG_RUNTIME_DIR -environment variable is not set. -.Ss SYNTAX -The syntax used to send commands is extremely simple. -Every command sent follows the form -.Dq (\-?)([0-9]*)(.*) -or in other words, an optional -.Sq \- -followed by an optional unsigned integer, followed by an optional string. -Starting at the beginning, a leading -.Sq \- -tells -.Nm -that you would like to remove a block from the status bar. -If the command does not begin with a -.Sq \- -then -.Nm -will attempt to create/update a block instead. -.Pp -Next, you can optionally provide a number which represents the block you want -to act upon. -As an example, the command -.Dq \-10 -signals that you would like to remove block 10 from the status bar. -The command -.Dq 4 -on the other hand signals that you would like to create/update block 4. -If no block number is specified, then the specified action will be executed on -block 1. -It is important to note that the command -.Dq 0 -will be ignored as there is no block 0, however the command -.Dq \-0 -is special in that it deletes all the blocks from the status bar. -.Pp -Finally, after you have provided the optional -.Sq \- -flag and have selected the block to act upon, you can provide any string which -will be displayed in the selected block. -If the -.Sq \- -flag was specified then this string will be simply ignored. -.Sh OPTIONS -.Bl -tag -width Ds -.It Fl r -Add a single space of padding to the right of the status bar. -.It Fl s Ar seperator -Set the block seperator to the string specified by -.Ar seperator -as opposed to the default of -.Dq " | " . -.El -.Sh EXAMPLES -Display the current time in block 1, and the current date in block 2: -.Pp -.Dl "$ date \(aq+%H:%M\(aq >$XDG_RUNTIME_DIR/mstatus.pipe # Note the implicit \(aq1\(aq" -.Dl "$ date \(aq+2%d/%m/%Y\(aq >$XDG_RUNTIME_DIR/mstatus.pipe # Note the leading \(aq2\(aq" -.Pp -Delete the 5th block: -.Pp -.Dl $ echo \(aq-5\(aq >$XDG_RUNTIME_DIR/mstatus.pipe -.Pp -Replace the entire status bar with -.Dq Hello world! : -.Pp -.Dl $ printf \(aq-0\enHello world!\(aq >$XDG_RUNTIME_DIR/mstatus.pipe -.Sh EXIT STATUS -.Ex -std -.Sh NOTES -.Nm -always allocates enough memory to be able to hold as many blocks as the number -of the rightmost block. -This means that if you created a block in slots 1 and 2, memory will be -allocated for 2 blocks, however if you create a block in slots 1, 2, and 300, -then memory will be allocated for 300 blocks. -It is for this reason that you should avoid creating blocks in very high slots -without reason. -Luckily if deleting the block in slot 300 from the above example, the memory -for slots 3 to 300 will all be freed. -.Sh BUGS -As of the initial 1.0 version you cannot have a block which begins with a digit. -.Sh SEE ALSO -.Xr dwm 1 , -.Xr sway 1 -.Sh AUTHORS -.An Thomas Voss Aq Mt thomasvoss@live.com diff --git a/mstatus.c b/mstatus.c deleted file mode 100644 index 9e68eb3..0000000 --- a/mstatus.c +++ /dev/null @@ -1,318 +0,0 @@ -#define _GNU_SOURCE -#include <sys/types.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <errno.h> -#include <linux/limits.h> -#include <paths.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdnoreturn.h> -#include <signal.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#ifdef HAS_DWM - #include <X11/Xlib.h> -#endif - -#define CTOI(x) ((x) ^ 48) - -struct Block { - int pos; - char *text; - bool remove; -}; - -bool rflag; -const char *argv0; -struct { - char *str; - size_t len; -} seperator = {.str = " | ", .len = 3}; - -static noreturn void usage(void); -static noreturn void die(const char *); -static void *xrealloc(void *, size_t); -static void xfree(char **); -static void write_status(struct Block); -static bool process(char *, struct Block *); -static void create_fifo(char *); - -#ifdef HAS_DWM -static void daemonize(void); -static void xfork(void); -#endif - -void -usage(void) -{ - fprintf(stderr, "Usage: %s [-r] [-s seperator]\n", argv0); - exit(EXIT_FAILURE); -} - -void -die(const char *s) -{ - char *err = strerror(errno); - syslog(LOG_ERR, "%s: %s", s, err); - fprintf(stderr, "%s: %s: %s\n", argv0, s, err); - exit(EXIT_FAILURE); -} - -#ifdef HAS_DWM -void -xfork(void) -{ - pid_t pid = fork(); - if (pid == -1) - die("fork"); - if (pid != 0) - exit(EXIT_SUCCESS); -} -#endif - -void * -xrealloc(void *ptr, size_t size) -{ - void *ret; - if (!(ret = realloc(ptr, size))) - die("realloc"); - return ret; -} - -void -xfree(char **ptr) -{ - free(*ptr); - *ptr = NULL; -} - -void -write_status(struct Block b) -{ - static struct { - char **blocks; - int count; - size_t length; - } sb; - - if (b.remove) { - if (b.pos > sb.count) - return; - - /* b.remove && !b.pos is a special case to remove everything from the bar */ - if (!b.pos) { - for (int i = 0; i < sb.count; i++) - free(sb.blocks[i]); - sb.count = 0; - sb.blocks = xrealloc(sb.blocks, sizeof(char *)); - goto update_bar; - } - - /* If the block is not NULL we free it */ - if (sb.blocks[--b.pos]) { - sb.length -= strlen(sb.blocks[b.pos]); - xfree(&sb.blocks[b.pos]); - } - - /* If the block is the last one, we resize the bar to remove trailing NULL blocks */ - if (b.pos + 1 == sb.count) { - for (; !sb.blocks[b.pos] && b.pos; b.pos--) - sb.count--; - sb.blocks = xrealloc(sb.blocks, sizeof(char *) * ++b.pos); - } - goto update_bar; - } - - /* If the position exceeds the space allocated, allocate more blocks */ - if (b.pos > sb.count) { - sb.blocks = xrealloc(sb.blocks, sizeof(char *) * b.pos); - /* Make sure to set all the newly allocated blocks to NULL */ - for (int i = sb.count; i < b.pos; i++) - sb.blocks[i] = NULL; - sb.count = b.pos; - } - - /* If the block is NULL we dont need to bother with strlen and free */ - if (sb.blocks[--b.pos]) { - sb.length -= strlen(sb.blocks[b.pos]); - xfree(&sb.blocks[b.pos]); - } - if (!(sb.blocks[b.pos] = strdup(b.text))) - die("strdup"); - sb.length += strlen(b.text); - - /* The buffer to store the text that will be displayed in. It needs space for the text, the - * seperators between the different blocks, the NUL byte at the end, and the right padding - * space. - */ -update_bar:; - char buf[sb.length + (sb.count - 1) * seperator.len + 2]; - memset(buf, '\0', sizeof(buf)); - - /* Double loops so that the seperator isnt printed to the left of the first block */ - int i; - char *bufptr = buf; - for (i = 0; i < sb.count; i++) { - if (sb.blocks[i]) { - bufptr = stpcpy(buf, sb.blocks[i]); - break; - } - } - while (++i < sb.count) { - if (sb.blocks[i]) - bufptr = stpcpy(stpcpy(bufptr, seperator.str), sb.blocks[i]); - } - if (rflag) - strcat(buf, " "); - -#ifdef HAS_DWM - /* Xlib magic to set the DWM status */ - Display *dpy = XOpenDisplay(NULL); - int screen = DefaultScreen(dpy); - Window root = RootWindow(dpy, screen); - (void) XStoreName(dpy, root, buf); - (void) XCloseDisplay(dpy); -#else - puts(buf); -#endif -} - -bool -process(char *line, struct Block *b) -{ - if (*line == '-') { - b->remove = true; - line++; - } else - b->remove = false; - - if (!isdigit(*line)) - b->pos = 1; /* Default position */ - else { - b->pos = 0; - while (isdigit(*line)) - b->pos = b->pos * 10 + CTOI(*line++); - if (!b->pos && !b->remove) - return false; - } - - b->text = line; - return true; -} - -void -create_fifo(char *fifo_path) -{ - char *runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (runtime_dir) { - size_t end = strlen(runtime_dir) - 1; - if (runtime_dir[end] == '/') - runtime_dir[end] = '\0'; - sprintf(fifo_path, "%s/%s.pipe", runtime_dir, argv0); - } else - sprintf(fifo_path, _PATH_VARRUN "user/%d/%s.pipe", getuid(), argv0); - - umask(0); - -create_fifo: - if (mkfifo(fifo_path, DEFFILEMODE) == -1) { - if (errno == EEXIST) { - if (unlink(fifo_path) == -1) - die("unlink"); - goto create_fifo; - } else - die("mkfifo"); - } - - syslog(LOG_INFO, "Created input FIFO '%s'", fifo_path); -} - -#ifdef HAS_DWM -void -daemonize(void) -{ - xfork(); - if (setsid() == -1) - die("setsid"); - - (void) signal(SIGCHLD, SIG_IGN); - xfork(); - - (void) chdir("/"); - (void) close(STDIN_FILENO); - (void) close(STDOUT_FILENO); - (void) close(STDERR_FILENO); - - stdin = fopen(_PATH_DEVNULL, "r"); - stdout = fopen(_PATH_DEVNULL, "w+"); - stderr = fopen(_PATH_DEVNULL, "w+"); - - syslog(LOG_INFO, "Daemonized '%s'", argv0); -} -#endif - -int -main(int argc, char **argv) -{ - argv0 = argv[0]; - - int opt; - while ((opt = getopt(argc, argv, ":rs:")) != -1) { - switch (opt) { - case 'r': - rflag = true; - break; - case 's': - seperator.str = optarg; - seperator.len = strlen(optarg); - break; - default: - usage(); - } - } - - openlog(argv0, LOG_PID | LOG_CONS, -#ifdef HAS_DWM - LOG_DAEMON -#else - LOG_USER -#endif - ); - char fifo_path[PATH_MAX]; - create_fifo(fifo_path); -#ifdef HAS_DWM - daemonize(); -#endif - - char *line = NULL; - size_t len = 0; - while (true) { - FILE *fp; - if (!(fp = fopen(fifo_path, "r"))) - die("fopen"); - - ssize_t nr; - while ((nr = getline(&line, &len, fp)) != -1) { - /* For some reason output with newlines can cause performance issues */ - if (line[--nr] == '\n') - line[nr] = '\0'; - - syslog(LOG_DEBUG, "Recieved command '%s'", line); - - struct Block b; - if (!process(line, &b)) - continue; - write_status(b); - } - if (ferror(fp)) - die("getline"); - - (void) fclose(fp); - } - /* NOTREACHED */ -} |