Xinqi Bao's Git

simplify smprintf by using vasprintf
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2
3 /* global libraries */
4 #include <alsa/asoundlib.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10 #include <unistd.h>
11 #include <X11/Xlib.h>
12
13 /* local libraries */
14 #include "config.h"
15
16 /* functions */
17 void setstatus(char *str);
18 char *smprintf(char *fmt, ...);
19 char *get_battery();
20 char *get_cpu_temperature();
21 char *get_cpu_usage();
22 char *get_datetime();
23 char *get_ram_usage();
24 char *get_volume();
25 char *get_wifi_signal();
26
27 /* global variables */
28 static Display *dpy;
29
30 /* set statusbar (WM_NAME) */
31 void
32 setstatus(char *str)
33 {
34 XStoreName(dpy, DefaultRootWindow(dpy), str);
35 XSync(dpy, False);
36 }
37
38 /* smprintf function */
39 char *
40 smprintf(char *fmt, ...)
41 {
42 va_list fmtargs;
43 char *ret = NULL;
44 va_start(fmtargs, fmt);
45 if (vasprintf(&ret, fmt, fmtargs) < 0)
46 return NULL;
47 va_end(fmtargs);
48
49 return ret;
50 }
51
52 /* battery percentage */
53 char *
54 get_battery()
55 {
56 int now, full, perc;
57 FILE *fp;
58
59 /* open battery now file */
60 if (!(fp = fopen(batterynowfile, "r"))) {
61 fprintf(stderr, "Error opening battery file.");
62 exit(1);
63 }
64
65 /* read value */
66 fscanf(fp, "%i", &now);
67
68 /* close battery now file */
69 fclose(fp);
70
71 /* open battery full file */
72 if (!(fp = fopen(batteryfullfile, "r"))) {
73 fprintf(stderr, "Error opening battery file.");
74 exit(1);
75 }
76
77 /* read value */
78 fscanf(fp, "%i", &full);
79
80 /* close battery full file */
81 fclose(fp);
82
83 /* calculate percent */
84 perc = now / (full / 100);
85
86 /* return perc as string */
87 return smprintf("%d%%", perc);
88 }
89
90 /* cpu temperature */
91 char *
92 get_cpu_temperature()
93 {
94 int temperature;
95 FILE *fp;
96
97 /* open temperature file */
98 if (!(fp = fopen(tempfile, "r"))) {
99 fprintf(stderr, "Could not open temperature file.\n");
100 exit(1);
101 }
102
103 /* extract temperature */
104 fscanf(fp, "%d", &temperature);
105
106 /* close temperature file */
107 fclose(fp);
108
109 /* return temperature in degrees */
110 return smprintf("%d°C", temperature / 1000);
111 }
112
113 /* cpu percentage */
114 char *
115 get_cpu_usage()
116 {
117 int perc;
118 long double a[4], b[4];
119 FILE *fp;
120
121 /* open stat file */
122 if (!(fp = fopen("/proc/stat","r"))) {
123 fprintf(stderr, "Error opening stat file.");
124 exit(1);
125 }
126
127 /* read values */
128 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
129
130 /* close stat file */
131 fclose(fp);
132
133 /* wait a second (for avg values) */
134 sleep(1);
135
136 /* open stat file */
137 if (!(fp = fopen("/proc/stat","r"))) {
138 fprintf(stderr, "Error opening stat file.");
139 exit(1);
140 }
141
142 /* read values */
143 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
144
145 /* close stat file */
146 fclose(fp);
147
148 /* calculate avg in this second */
149 perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) / ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
150
151 /* return perc as string */
152 return smprintf("%d%%", perc);
153 }
154
155 /* date and time */
156 char *
157 get_datetime()
158 {
159 time_t tm;
160 size_t bufsize = 64;
161 char *buf = malloc(bufsize);
162
163 /* get time in format */
164 time(&tm);
165 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
166 fprintf(stderr, "Strftime failed.\n");
167 exit(1);
168 }
169
170 /* return time */
171 return smprintf("%s", buf);
172 }
173
174 /* ram percentage */
175 char *
176 get_ram_usage()
177 {
178 int perc;
179 long total, free, buffers, cached;
180 FILE *fp;
181
182 /* open meminfo file */
183 if (!(fp = fopen("/proc/meminfo", "r"))) {
184 fprintf(stderr, "Error opening meminfo file.");
185 exit(1);
186 }
187
188 /* read the values */
189 fscanf(fp, "MemTotal: %ld kB\n", &total);
190 fscanf(fp, "MemFree: %ld kB\n", &free);
191 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
192 fscanf(fp, "Cached: %ld kB\n", &cached);
193
194 /* close meminfo file */
195 fclose(fp);
196
197 /* calculate percentage */
198 perc = 100 * ((total - free) - (buffers + cached)) / total;
199
200 /* return perc as string */
201 return smprintf("%d%%", perc);
202 }
203
204 /* alsa volume percentage */
205 char *
206 get_volume()
207 {
208 int mute = 0;
209 long vol = 0, max = 0, min = 0;
210
211 /* get volume from alsa */
212 snd_mixer_t *handle;
213 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
214 snd_mixer_selem_id_t *vol_info, *mute_info;
215 snd_mixer_open(&handle, 0);
216 snd_mixer_attach(handle, soundcard);
217 snd_mixer_selem_register(handle, NULL, NULL);
218 snd_mixer_load(handle);
219 snd_mixer_selem_id_malloc(&vol_info);
220 snd_mixer_selem_id_malloc(&mute_info);
221 snd_mixer_selem_id_set_name(vol_info, channel);
222 snd_mixer_selem_id_set_name(mute_info, channel);
223 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
224 mas_mixer = snd_mixer_find_selem(handle, mute_info);
225 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
226 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
227 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
228 if (vol_info)
229 snd_mixer_selem_id_free(vol_info);
230 if (mute_info)
231 snd_mixer_selem_id_free(mute_info);
232 if (handle)
233 snd_mixer_close(handle);
234
235 /* return the string (mute) */
236 if (!mute)
237 return smprintf("mute");
238 else
239 return smprintf("%d%%", (vol * 100) / max);
240 }
241
242 /* wifi percentage */
243 char *
244 get_wifi_signal()
245 {
246 int bufsize = 255;
247 int strength;
248 char buf[bufsize];
249 char *datastart;
250 char path_start[16] = "/sys/class/net/";
251 char path_end[11] = "/operstate";
252 char path[32];
253 char status[5];
254 char needle[sizeof wificard + 1];
255 FILE *fp;
256
257 /* generate the path name */
258 memset(path, 0, sizeof path);
259 strcat(path, path_start);
260 strcat(path, wificard);
261 strcat(path, path_end);
262
263 /* open wifi file */
264 if(!(fp = fopen(path, "r"))) {
265 fprintf(stderr, "Error opening wifi operstate file.");
266 exit(1);
267 }
268
269 /* read the status */
270 fgets(status, 5, fp);
271
272 /* close wifi file */
273 fclose(fp);
274
275 /* check if interface down */
276 if(strcmp(status, "up\n") != 0){
277 return "n/a";
278 }
279
280 /* open wifi file */
281 if (!(fp = fopen("/proc/net/wireless", "r"))) {
282 fprintf(stderr, "Error opening wireless file.");
283 exit(1);
284 }
285
286 /* extract the signal strength */
287 strcpy(needle, wificard);
288 strcat(needle, ":");
289 fgets(buf, bufsize, fp);
290 fgets(buf, bufsize, fp);
291 fgets(buf, bufsize, fp);
292 if ((datastart = strstr(buf, needle)) != NULL) {
293 datastart = strstr(buf, ":");
294 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
295 }
296
297 /* close wifi file */
298 fclose(fp);
299
300 /* return strength in percent */
301 return smprintf("%d%%", strength);
302 }
303
304 /* main function */
305 int
306 main()
307 {
308 char status[1024];
309 char *battery = NULL;
310 char *cpu_temperature = NULL;
311 char *cpu_usage = NULL;
312 char *datetime = NULL;
313 char *ram_usage = NULL;
314 char *volume = NULL;
315 char *wifi_signal = NULL;
316
317 /* open display */
318 if (!(dpy = XOpenDisplay(0x0))) {
319 fprintf(stderr, "Cannot open display!\n");
320 exit(1);
321 }
322
323 /* return status every second */
324 for (;;) {
325 /* assign the values */
326 battery = get_battery();
327 cpu_temperature = get_cpu_temperature();
328 cpu_usage = get_cpu_usage();
329 datetime = get_datetime();
330 ram_usage = get_ram_usage();
331 volume = get_volume();
332 wifi_signal = get_wifi_signal();
333
334 /* return the status */
335 sprintf(status, FORMATSTRING, ARGUMENTS);
336 setstatus(status);
337
338 /* free the values */
339 free(battery);
340 free(cpu_temperature);
341 free(cpu_usage);
342 free(datetime);
343 free(ram_usage);
344 free(volume);
345 free(wifi_signal);
346 }
347
348 /* close display */
349 XCloseDisplay(dpy);
350
351 /* exit successfully */
352 return 0;
353 }