slstatus/components/battery.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

181 lines
3.5 KiB
C

/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "../util.h"
#if defined(__linux__)
#include <limits.h>
const char *
battery_perc(const char *bat)
{
int perc;
char path[PATH_MAX];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/capacity",
bat) < 0) {
return NULL;
}
if (pscanf(path, "%d", &perc) != 1) {
return NULL;
}
return bprintf("%d", perc);
}
const char *
battery_state(const char *bat)
{
static struct {
char *state;
char *symbol;
} map[] = {
{ "Charging", "+" },
{ "Discharging", "-" },
};
size_t i;
char path[PATH_MAX], state[12];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/status",
bat) < 0) {
return NULL;
}
if (pscanf(path, "%12s", state) != 1) {
return NULL;
}
for (i = 0; i < LEN(map); i++) {
if (!strcmp(map[i].state, state)) {
break;
}
}
return (i == LEN(map)) ? "?" : map[i].symbol;
}
const char *
battery_remaining(const char *bat)
{
int charge_now, current_now, m, h;
float timeleft;
char path[PATH_MAX], state[12];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/status",
bat) < 0) {
return NULL;
}
if (pscanf(path, "%12s", state) != 1) {
return NULL;
}
if (!strcmp(state, "Discharging")) {
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/charge_now",
bat) < 0) {
return NULL;
}
if (pscanf(path, "%d", &charge_now) != 1) {
return NULL;
}
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/current_now",
bat) < 0) {
return NULL;
}
if (pscanf(path, "%d", &current_now) != 1) {
return NULL;
}
timeleft = (float)charge_now / (float)current_now;
h = timeleft;
m = (timeleft - (float)h) * 60;
return bprintf("%dh %dm", h, m);
}
return "";
}
#elif defined(__OpenBSD__)
#include <fcntl.h>
#include <machine/apmvar.h>
#include <sys/ioctl.h>
#include <unistd.h>
static int
load_apm_power_info(struct apm_power_info *apm_info)
{
int fd;
fd = open("/dev/apm", O_RDONLY);
if (fd < 0) {
warn("open '/dev/apm':");
return 0;
}
memset(apm_info, 0, sizeof(struct apm_power_info));
if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
warn("ioctl 'APM_IOC_GETPOWER':");
close(fd);
return 0;
}
return close(fd), 1;
}
const char *
battery_perc(const char *unused)
{
struct apm_power_info apm_info;
if (load_apm_power_info(&apm_info)) {
return bprintf("%d", apm_info.battery_life);
}
return NULL;
}
const char *
battery_state(const char *unused)
{
struct {
unsigned int state;
char *symbol;
} map[] = {
{ APM_AC_ON, "+" },
{ APM_AC_OFF, "-" },
};
struct apm_power_info apm_info;
size_t i;
if (load_apm_power_info(&apm_info)) {
for (i = 0; i < LEN(map); i++) {
if (map[i].state == apm_info.ac_state) {
break;
}
}
return (i == LEN(map)) ? "?" : map[i].symbol;
}
return NULL;
}
const char *
battery_remaining(const char *unused)
{
struct apm_power_info apm_info;
if (load_apm_power_info(&apm_info)) {
if (apm_info.ac_state != APM_AC_ON) {
return bprintf("%uh %02um", apm_info.minutes_left / 60,
apm_info.minutes_left % 60);
} else {
return "";
}
}
return NULL;
}
#endif