![Laslo Hunhold](/assets/img/avatar_default.png)
Given slstatus is a tool that runs in the background, most likely run from .xinitrc, it's important to prepend the name of the tool to error messages so it becomes clear where the error is coming from. To make this much more consistent, this commit adds warn() and die() utility functions consistent with other suckless projects and adapts all calls to fprintf(stderr, *) to the warn() and die() functions, greatly increasing the readability of the code.
141 lines
2.6 KiB
C
141 lines
2.6 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <X11/Xlib.h>
|
|
|
|
#include "arg.h"
|
|
#include "slstatus.h"
|
|
#include "util.h"
|
|
|
|
struct arg {
|
|
const char *(*func)();
|
|
const char *fmt;
|
|
const char *args;
|
|
};
|
|
|
|
char buf[1024];
|
|
static int done;
|
|
static Display *dpy;
|
|
|
|
#include "config.h"
|
|
|
|
static void
|
|
terminate(const int signo)
|
|
{
|
|
(void)signo;
|
|
|
|
done = 1;
|
|
}
|
|
|
|
static void
|
|
difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
|
|
{
|
|
res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec);
|
|
res->tv_nsec = a->tv_nsec - b->tv_nsec +
|
|
(a->tv_nsec < b->tv_nsec) * 1000000000;
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
die("usage: %s [-s]", argv0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct sigaction act;
|
|
struct timespec start, current, diff, intspec, wait;
|
|
size_t i, len;
|
|
int sflag, ret;
|
|
char status[MAXLEN];
|
|
const char *res;
|
|
|
|
sflag = 0;
|
|
ARGBEGIN {
|
|
case 's':
|
|
sflag = 1;
|
|
break;
|
|
default:
|
|
usage();
|
|
} ARGEND
|
|
|
|
if (argc) {
|
|
usage();
|
|
}
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
act.sa_handler = terminate;
|
|
sigaction(SIGINT, &act, NULL);
|
|
sigaction(SIGTERM, &act, NULL);
|
|
|
|
if (sflag) {
|
|
setbuf(stdout, NULL);
|
|
}
|
|
|
|
if (!sflag && !(dpy = XOpenDisplay(NULL))) {
|
|
die("XOpenDisplay: Failed to open display");
|
|
}
|
|
|
|
while (!done) {
|
|
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
|
|
die("clock_gettime:");
|
|
}
|
|
|
|
status[0] = '\0';
|
|
for (i = len = 0; i < LEN(args); i++) {
|
|
if (!(res = args[i].func(args[i].args))) {
|
|
res = unknown_str;
|
|
}
|
|
if ((ret = snprintf(status + len, sizeof(status) - len,
|
|
args[i].fmt, res)) < 0) {
|
|
warn("snprintf:");
|
|
break;
|
|
} else if ((size_t)ret >= sizeof(status) - len) {
|
|
warn("snprintf: Output truncated");
|
|
break;
|
|
}
|
|
len += ret;
|
|
}
|
|
|
|
if (sflag) {
|
|
printf("%s\n", status);
|
|
} else {
|
|
if (XStoreName(dpy, DefaultRootWindow(dpy), status) < 0) {
|
|
die("XStoreName: Allocation failed");
|
|
}
|
|
XFlush(dpy);
|
|
}
|
|
|
|
if (!done) {
|
|
if (clock_gettime(CLOCK_MONOTONIC, ¤t) < 0) {
|
|
die("clock_gettime:");
|
|
}
|
|
difftimespec(&diff, ¤t, &start);
|
|
|
|
intspec.tv_sec = interval / 1000;
|
|
intspec.tv_nsec = (interval % 1000) * 1000000;
|
|
difftimespec(&wait, &intspec, &diff);
|
|
|
|
if (wait.tv_sec >= 0) {
|
|
if (nanosleep(&wait, NULL) < 0 &&
|
|
errno != EINTR) {
|
|
die("nanosleep:");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!sflag) {
|
|
XStoreName(dpy, DefaultRootWindow(dpy), NULL);
|
|
if (XCloseDisplay(dpy) < 0) {
|
|
die("XCloseDisplay: Failed to close display");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|