Xinqi Bao's Git

Simplify format specifiers for uintmax_t
[slstatus.git] / components / battery.c
1 /* See LICENSE file for copyright and license details. */
2 #include <stdio.h>
3 #include <string.h>
4
5 #include "../util.h"
6
7 #if defined(__linux__)
8 #include <limits.h>
9 #include <stdint.h>
10 #include <unistd.h>
11
12 static const char *
13 pick(const char *bat, const char *f1, const char *f2, char *path,
14 size_t length)
15 {
16 if (esnprintf(path, length, f1, bat) > 0 &&
17 access(path, R_OK) == 0) {
18 return f1;
19 }
20
21 if (esnprintf(path, length, f2, bat) > 0 &&
22 access(path, R_OK) == 0) {
23 return f2;
24 }
25
26 return NULL;
27 }
28
29 const char *
30 battery_perc(const char *bat)
31 {
32 int perc;
33 char path[PATH_MAX];
34
35 if (esnprintf(path, sizeof(path),
36 "/sys/class/power_supply/%s/capacity",
37 bat) < 0) {
38 return NULL;
39 }
40 if (pscanf(path, "%d", &perc) != 1) {
41 return NULL;
42 }
43
44 return bprintf("%d", perc);
45 }
46
47 const char *
48 battery_state(const char *bat)
49 {
50 static struct {
51 char *state;
52 char *symbol;
53 } map[] = {
54 { "Charging", "+" },
55 { "Discharging", "-" },
56 };
57 size_t i;
58 char path[PATH_MAX], state[12];
59
60 if (esnprintf(path, sizeof(path),
61 "/sys/class/power_supply/%s/status",
62 bat) < 0) {
63 return NULL;
64 }
65 if (pscanf(path, "%12s", state) != 1) {
66 return NULL;
67 }
68
69 for (i = 0; i < LEN(map); i++) {
70 if (!strcmp(map[i].state, state)) {
71 break;
72 }
73 }
74 return (i == LEN(map)) ? "?" : map[i].symbol;
75 }
76
77 const char *
78 battery_remaining(const char *bat)
79 {
80 uintmax_t charge_now, current_now, m, h;
81 double timeleft;
82 char path[PATH_MAX], state[12];
83
84 if (esnprintf(path, sizeof(path),
85 "/sys/class/power_supply/%s/status",
86 bat) < 0) {
87 return NULL;
88 }
89 if (pscanf(path, "%12s", state) != 1) {
90 return NULL;
91 }
92
93 if (!pick(bat, "/sys/class/power_supply/%s/charge_now",
94 "/sys/class/power_supply/%s/energy_now",
95 path, sizeof(path)) ||
96 pscanf(path, "%ju", &charge_now) < 0) {
97 return NULL;
98 }
99
100 if (!strcmp(state, "Discharging")) {
101 if (!pick(bat, "/sys/class/power_supply/%s/current_now",
102 "/sys/class/power_supply/%s/power_now", path,
103 sizeof(path)) ||
104 pscanf(path, "%ju", &current_now) < 0) {
105 return NULL;
106 }
107
108 if (current_now == 0) {
109 return NULL;
110 }
111
112 timeleft = (double)charge_now / (double)current_now;
113 h = timeleft;
114 m = (timeleft - (double)h) * 60;
115
116 return bprintf("%juh %jum", h, m);
117 }
118
119 return "";
120 }
121 #elif defined(__OpenBSD__)
122 #include <fcntl.h>
123 #include <machine/apmvar.h>
124 #include <sys/ioctl.h>
125 #include <unistd.h>
126
127 static int
128 load_apm_power_info(struct apm_power_info *apm_info)
129 {
130 int fd;
131
132 fd = open("/dev/apm", O_RDONLY);
133 if (fd < 0) {
134 warn("open '/dev/apm':");
135 return 0;
136 }
137
138 memset(apm_info, 0, sizeof(struct apm_power_info));
139 if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
140 warn("ioctl 'APM_IOC_GETPOWER':");
141 close(fd);
142 return 0;
143 }
144 return close(fd), 1;
145 }
146
147 const char *
148 battery_perc(const char *unused)
149 {
150 struct apm_power_info apm_info;
151
152 if (load_apm_power_info(&apm_info)) {
153 return bprintf("%d", apm_info.battery_life);
154 }
155
156 return NULL;
157 }
158
159 const char *
160 battery_state(const char *unused)
161 {
162 struct {
163 unsigned int state;
164 char *symbol;
165 } map[] = {
166 { APM_AC_ON, "+" },
167 { APM_AC_OFF, "-" },
168 };
169 struct apm_power_info apm_info;
170 size_t i;
171
172 if (load_apm_power_info(&apm_info)) {
173 for (i = 0; i < LEN(map); i++) {
174 if (map[i].state == apm_info.ac_state) {
175 break;
176 }
177 }
178 return (i == LEN(map)) ? "?" : map[i].symbol;
179 }
180
181 return NULL;
182 }
183
184 const char *
185 battery_remaining(const char *unused)
186 {
187 struct apm_power_info apm_info;
188
189 if (load_apm_power_info(&apm_info)) {
190 if (apm_info.ac_state != APM_AC_ON) {
191 return bprintf("%uh %02um",
192 apm_info.minutes_left / 60,
193 apm_info.minutes_left % 60);
194 } else {
195 return "";
196 }
197 }
198
199 return NULL;
200 }
201 #endif