public
Created

mparser - a simple parser for monsterwm's output

  • Download Gist
Makefile
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# Makefile for mparser - see UNLICENSE for nonlicense and noncopyright information
 
VERSION = cookies-git
NAME = mparser
 
PREFIX ?= /usr/local
BINDIR ?= ${PREFIX}/bin
 
INCS = -I. -I/usr/include
LIBS = -L/usr/lib -lc
 
CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os ${INCS} -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\"
LDFLAGS = -s ${LIBS}
 
CC = cc
EXEC = ${NAME}
 
SRC = ${NAME}.c
OBJ = ${SRC:.c=.o}
 
all: options ${NAME}
 
options:
@echo ${NAME} build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
 
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
 
.o:
@echo CC -o $@
@${CC} -o $@ $< ${LDFLAGS}
 
clean:
@echo cleaning
@rm -fv ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz
 
install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
@install -Dm755 ${NAME} ${DESTDIR}${PREFIX}/bin/${NAME}
 
uninstall:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/${NAME}
 
.PHONY: all options clean install uninstall
mparser.c
C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
/* a parser for monsterwm output */
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <err.h>
#include <regex.h>
 
#define URGENT ""
#define SEPARATOR "::"
#define DESKFMT "[ %s %d ] %s "
#define OUTFMT "&L%s &R%s\n"
 
static const char* commands[] = {
"statusbar",
"date +\"%F %R\"",
};
 
static const char* desktops[] = {
"web", "dev", "foo", "irc",
};
 
static const char* layouts[] = {
"[T]", /* tile */
"[M]", /* monocle */
"[B]", /* bstack */
"[G]", /* grid */
"[F]", /* fibonacci */
};
 
#define USAGE "usage: mparser [-h] /path/to/fifo"
#define FIFO "/tmp/monsterwm.fifo"
#define LENGTH(x) (sizeof(x)/sizeof(*x))
 
#ifndef PATH_MAX
#define PATH_MAX 2048
#endif
 
#ifndef LINE_MAX
#define LINE_MAX 1024
#endif
 
int main(int argc, char *argv[]) {
char fifopath[PATH_MAX];
int fifofd;
char *line = calloc(1, LINE_MAX);
int len = -1;
 
/* parse arguments */
if (argc == 2)
if (strncmp(argv[1], "-h", 3) == 0)
errx(EXIT_SUCCESS, "%s", USAGE);
else
strncpy(fifopath, argv[1], sizeof(fifopath));
else if (argc > 2)
errx(EXIT_FAILURE, "%s", USAGE);
else
strncpy(fifopath, FIFO, sizeof(fifopath));
 
/* create and open fifo */
//if (open(fifopath, O_RDONLY) != -1 && errno != ENOENT)
// unlink(fifopath);
if (mkfifo(fifopath, 0600) == -1 && errno != EEXIST)
err(EXIT_FAILURE, "cannot create fifo: %s", fifopath);
if ((fifofd = open(fifopath, O_RDONLY)) == -1)
err(EXIT_FAILURE, "cannot open fifo from path: %s", fifopath);
 
/* create regex to match line */
regex_t re;
char *pattern = "^([0-9]+:[0-9]+:[0-9]+:[01]:[01] ?)+";
if (regcomp(&re, pattern, REG_EXTENDED) != 0)
err(EXIT_FAILURE, "failed to compile pattern: %s", pattern);
 
/* wait for data */
while ((len = read(fifofd, line, LINE_MAX)) >= 0) {
if (len == 0) {
close(fifofd);
if ((fifofd = open(fifopath, O_RDONLY)) == -1)
err(EXIT_FAILURE, "cannot open fifo from path: %s", fifopath);
continue;
}
 
/* check if line is valid -- weak regex here */
if (regexec(&re, line, 0, NULL, 0) != 0)
goto clean;
 
/* parse line and format desktop info */
int d, w, m, c, u;
char output[LINE_MAX], mode[128];
for (char deskout[LINE_MAX], *desk = strtok(line, " ");
desk != NULL && sscanf(desk, "%d:%d:%d:%d:%d", &d, &w, &m, &c, &u) == 5;
desk = strtok(NULL, " ")) {
snprintf(deskout, sizeof(deskout), DESKFMT, desktops[d], w, SEPARATOR);
if (c) strncpy(mode, layouts[m], sizeof(mode));
strncat(output, deskout, sizeof(output));
}
 
/* run the commands and collect output */
FILE *stream;
char cmdout[LINE_MAX];
cmdout[0] = '\0';
for (unsigned int cmd = 0; cmd < LENGTH(commands); cmd++) {
char *cmdline = NULL;
size_t len = 0;
 
if ((stream = popen(commands[cmd], "r")) == NULL)
warn("failed to execute command: %s", commands[cmd]);
if (getline(&cmdline, &len, stream) == -1)
warn("failed to get output for command: %s", commands[cmd]);
 
pclose(stream);
cmdline[strlen(cmdline) - 1] = '\0';
strncat(cmdout, cmdline, sizeof(cmdout));
free(cmdline);
}
 
/* print data */
strncat(output, mode, sizeof(output));
fprintf(stdout, OUTFMT, output, cmdout);
fflush(stdout);
 
/* clear buffer */
clean:
memset(line, 0x00, sizeof(line));
memset(output, 0x00, sizeof(output));
memset(cmdout, 0x00, sizeof(cmdout));
}
 
/* cleanup */
regfree(&re);
free(line);
line = NULL;
close(fifofd);
 
/* all was good :] */
return EXIT_SUCCESS;
}
mparser /tmp/monsterwm.fifo | while read -r; do xsetroot -name "$REPLY"; done &
some_sorta_bar &
monsterwm | tee -a /tmp/monsterwm.fifo

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.