ustatus

Yet another stupid dwm status tool

git clone https://git.8pit.net/ustatus.git

  1/* See LICENSE for license details. */
  2
  3#include <assert.h>
  4#include <err.h>
  5#include <stdarg.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9#include <time.h>
 10#include <limits.h>
 11#include <unistd.h>
 12
 13#include <sys/types.h>
 14#include <tinyalsa/asoundlib.h>
 15
 16static size_t alsavol(char*, size_t);
 17static size_t batcap(char*, size_t);
 18static size_t loadavg(char*, size_t);
 19static size_t curtime(char*, size_t);
 20static size_t separator(char*, size_t);
 21
 22#include "config.h"
 23
 24enum {
 25	STATUSSZ = 128,
 26};
 27
 28static char ststr[STATUSSZ];
 29
 30static int
 31xsnprintf(char *restrict s, size_t n, const char *restrict fmt, ...)
 32{
 33	int ret;
 34	va_list ap;
 35
 36	va_start(ap, fmt);
 37	ret = vsnprintf(s, n, fmt, ap);
 38	va_end(ap);
 39
 40	if (ret < 0) {
 41		err(EXIT_FAILURE, "snprintf failed");
 42	} else if ((size_t)ret >= n) {
 43		warnx("snprintf: insufficient buffer size");
 44		ret = n;
 45	}
 46
 47	return ret;
 48}
 49
 50static double
 51readnum(char *bfp, char *fn)
 52{
 53	int ret;
 54	FILE *file;
 55	size_t rclen;
 56	char buf[16], fp[PATH_MAX + 1], *rc;
 57
 58	rc = NULL;
 59	if ((ret = snprintf(fp, sizeof(fp), "%s/%s", bfp, fn)) < 0)
 60		errx(EXIT_FAILURE, "snprintf failed");
 61	else if ((size_t)ret >= sizeof(fp))
 62		errx(EXIT_FAILURE, "buffer 'fp' is too short");
 63
 64	if (!(file = fopen(fp, "r")))
 65		err(EXIT_FAILURE, "couldn't open '%s'", fp);
 66
 67	if (!(rc = fgets(buf, 16, file))) {
 68		fclose(file);
 69		errx(EXIT_FAILURE, "'%s' seems to be empty", fp);
 70	}
 71
 72	rclen = strlen(buf);
 73	if (rc[rclen - 1] == '\n')
 74		rc[rclen - 1] = '\0';
 75
 76	fclose(file);
 77	return atof(rc);
 78}
 79
 80static size_t
 81actlstr(char *buf, size_t n, char *ch, struct mixer *mx) {
 82	size_t ret;
 83	char *status;
 84	struct mixer_ctl *ctl;
 85
 86	if (!(ctl = mixer_get_ctl_by_name(mx, ch))) {
 87		mixer_close(mx);
 88		errx(EXIT_FAILURE, "couldn't find mixer ctl '%s'\n", ch);
 89	}
 90
 91	switch (mixer_ctl_get_type(ctl)) {
 92	case MIXER_CTL_TYPE_INT:
 93		return xsnprintf(buf, n, "%d%%",
 94			mixer_ctl_get_percent(ctl, 0));
 95	case MIXER_CTL_TYPE_BOOL:
 96		status = mixer_ctl_get_value(ctl, 0) ? "On" : "Off";
 97		ret = stpncpy(buf, status, n) - buf;
 98		break;
 99	default:
100		mixer_close(mx);
101		errx(EXIT_FAILURE, "unsupported ctl type '%s'\n",
102			mixer_ctl_get_type_string(ctl));
103	};
104
105	return ret;
106}
107
108static size_t
109batcap(char *dest, size_t n)
110{
111	int cap;
112
113	cap = readnum((char*)sysbat, "capacity");
114	return xsnprintf(dest, n, "%d%%", cap);
115}
116
117static size_t
118alsavol(char *dest, size_t n)
119{
120	size_t ret;
121	struct mixer *mx;
122
123	if (!(mx = mixer_open(sndcrd)))
124		errx(EXIT_FAILURE, "couldn't open mixer for card %d\n", sndcrd);
125
126	ret = actlstr(dest, n, (char*)swtchname, mx);
127	if (strcmp(dest, "Off"))
128		ret = actlstr(dest, n, (char*)volumname, mx);
129
130	mixer_close(mx);
131	return ret;
132}
133
134static size_t
135loadavg(char* dest, size_t n)
136{
137	double avgs[3];
138
139	if (!getloadavg(avgs, 3))
140		err(EXIT_FAILURE, "getloadavg failed");
141
142	return xsnprintf(dest, n, "%.2f %.2f %.2f",
143		avgs[0], avgs[1], avgs[2]);
144}
145
146static size_t
147curtime(char *dest, size_t n)
148{
149	time_t tim;
150	struct tm *timtm;
151
152	if ((tim = time(NULL)) == (time_t)-1)
153		err(EXIT_FAILURE, "time failed");
154
155	if (!(timtm = localtime(&tim)))
156		err(EXIT_FAILURE, "localtime failed");
157
158	return strftime(dest, n, timefmt, timtm);
159}
160
161static size_t
162separator(char *dest, size_t n)
163{
164	return stpncpy(dest, statsep, n) - dest;
165}
166
167int
168main(void)
169{
170	size_t i, x, fns, max;
171
172	max = STATUSSZ - 1;
173	fns = sizeof(sfuncs) / sizeof(sfuncs[0]);
174
175	for (;;) {
176		for (i = 0, x = 0; i < fns && x < max; i++) {
177			assert(max >= x);
178			x += (*sfuncs[i])(&(ststr[x]), max - x);
179		}
180
181		assert(x < STATUSSZ);
182		ststr[x] = '\0';
183
184		printf("%s\n", ststr);
185		fflush(stdout);
186		sleep(delay);
187	}
188
189	return EXIT_SUCCESS;
190}