slstatus/slstatus.c
Laslo Hunhold 80fc20d1d6 Add warn() and die()
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.
2018-05-18 11:13:05 +02:00

142 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, &current) < 0) {
die("clock_gettime:");
}
difftimespec(&diff, &current, &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;
}