slstatus/slstatus.c
Laslo Hunhold 422cadfd5f Implement esnprintf() and make formatted calls more efficient
Within the components, snprintf() was unchecked and had inefficient
calls in some places.
We implement esnprintf() that does all the dirty laundry for us
and use it exclusively now.
2018-05-19 19:44:02 +02:00

137 lines
2.4 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 = esnprintf(status + len, sizeof(status) - len,
args[i].fmt, res)) < 0) {
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;
}