Skip to content

Instantly share code, notes, and snippets.

@c00kiemon5ter
Created April 9, 2012 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c00kiemon5ter/2343738 to your computer and use it in GitHub Desktop.
Save c00kiemon5ter/2343738 to your computer and use it in GitHub Desktop.
mparser - a simple parser for monsterwm's output
# 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
/* 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;
}
@c00kiemon5ter
Copy link
Author

mparser /tmp/monsterwm.fifo | while read -r; do xsetroot -name "$REPLY"; done &
some_sorta_bar &
monsterwm | tee -a /tmp/monsterwm.fifo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment