Properly output JSON with libyajl

This commit is contained in:
Michael Stapelberg 2012-03-25 20:55:55 +02:00
parent afb0525235
commit 12b1bfa9b8
18 changed files with 330 additions and 234 deletions

View File

@ -17,6 +17,7 @@ CPPFLAGS+=-DSYSCONFDIR=\"$(SYSCONFDIR)\"
CPPFLAGS+=-DVERSION=\"${GIT_VERSION}\"
CFLAGS+=-Iinclude
LIBS+=-lconfuse
LIBS+=-lyajl
VERSION:=$(shell git describe --tags --abbrev=0)
GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1))"

2
debian/control vendored
View File

@ -3,7 +3,7 @@ Section: utils
Priority: extra
Maintainer: Michael Stapelberg <michael@stapelberg.de>
DM-Upload-Allowed: yes
Build-Depends: debhelper (>= 5), libiw-dev [linux-any], libconfuse-dev, asciidoc, xmlto, libcap2-bin [linux-any], libasound2-dev [linux-any], libbsd-dev [kfreebsd-any]
Build-Depends: debhelper (>= 5), libiw-dev [linux-any], libconfuse-dev, asciidoc, xmlto, libcap2-bin [linux-any], libasound2-dev [linux-any], libbsd-dev [kfreebsd-any], libyajl-dev
Standards-Version: 3.9.2
Homepage: http://i3wm.org/i3status

View File

@ -28,6 +28,8 @@
#include <sys/time.h>
#include <locale.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
#define exit_if_null(pointer, ...) { if (pointer == NULL) die(__VA_ARGS__); }
@ -110,7 +112,8 @@ static char *resolve_tilde(const char *path) {
head = globbuf.gl_pathv[0];
result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
strncpy(result, head, strlen(head));
strncat(result, tail, strlen(tail));
if (tail)
strncat(result, tail, strlen(tail));
}
globfree(&globbuf);
@ -343,10 +346,15 @@ int main(int argc, char *argv[]) {
|| !valid_color(cfg_getstr(cfg_general, "color_separator")))
die("Bad color format");
yajl_gen json_gen = yajl_gen_alloc(NULL);
if (output_format == O_I3BAR) {
/* Initialize the i3bar protocol. See i3/docs/i3bar-protocol
* for details. */
printf("{\"version\":1}\n[\n");
fflush(stdout);
yajl_gen_array_open(json_gen);
yajl_gen_clear(json_gen);
}
if ((general_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
@ -354,6 +362,14 @@ int main(int argc, char *argv[]) {
int interval = cfg_getint(cfg_general, "interval");
/* One memory page which each plugin can use to buffer output.
* Even though its unclean, we just assume that the user will not
* specify a format string which expands to something longer than 4096
* bytes given that the output of i3status is used to display
* information on screen, more than 1024 characters for the full line
* (!), not individual plugins, seem very unlikely. */
char buffer[4096];
struct tm tm;
while (1) {
struct timeval tv;
@ -365,54 +381,97 @@ int main(int argc, char *argv[]) {
current_tm = &tm;
}
if (output_format == O_I3BAR)
printf("[");
yajl_gen_array_open(json_gen);
for (j = 0; j < cfg_size(cfg, "order"); j++) {
if (j > 0)
print_seperator();
const char *current = cfg_getnstr(cfg, "order", j);
CASE_SEC("ipv6")
print_ipv6_info(cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
CASE_SEC("ipv6") {
SEC_OPEN_MAP("ipv6");
print_ipv6_info(json_gen, buffer, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("wireless")
print_wireless_info(title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
CASE_SEC_TITLE("wireless") {
SEC_OPEN_MAP("wireless");
print_wireless_info(json_gen, buffer, title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("ethernet")
print_eth_info(title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
CASE_SEC_TITLE("ethernet") {
SEC_OPEN_MAP("ethernet");
print_eth_info(json_gen, buffer, title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("battery")
print_battery_info(atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getbool(sec, "last_full_capacity"));
CASE_SEC_TITLE("battery") {
SEC_OPEN_MAP("battery");
print_battery_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getbool(sec, "last_full_capacity"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("run_watch")
print_run_watch(title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
CASE_SEC_TITLE("run_watch") {
SEC_OPEN_MAP("run_watch");
print_run_watch(json_gen, buffer, title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("disk")
print_disk_info(title, cfg_getstr(sec, "format"));
CASE_SEC_TITLE("disk") {
SEC_OPEN_MAP("disk_info");
print_disk_info(json_gen, buffer, title, cfg_getstr(sec, "format"));
SEC_CLOSE_MAP;
}
CASE_SEC("load")
print_load(cfg_getstr(sec, "format"));
CASE_SEC("load") {
SEC_OPEN_MAP("load");
print_load(json_gen, buffer, cfg_getstr(sec, "format"));
SEC_CLOSE_MAP;
}
CASE_SEC("time")
print_time(cfg_getstr(sec, "format"), current_tm);
CASE_SEC("time") {
SEC_OPEN_MAP("time");
print_time(json_gen, buffer, cfg_getstr(sec, "format"), current_tm);
SEC_CLOSE_MAP;
}
CASE_SEC("ddate")
print_ddate(cfg_getstr(sec, "format"), current_tm);
CASE_SEC("ddate") {
SEC_OPEN_MAP("ddate");
print_ddate(json_gen, buffer, cfg_getstr(sec, "format"), current_tm);
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("volume")
print_volume(cfg_getstr(sec, "format"),
CASE_SEC_TITLE("volume") {
SEC_OPEN_MAP("volume");
print_volume(json_gen, buffer, cfg_getstr(sec, "format"),
cfg_getstr(sec, "device"),
cfg_getstr(sec, "mixer"),
cfg_getint(sec, "mixer_idx"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("cpu_temperature")
print_cpu_temperature_info(atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
CASE_SEC_TITLE("cpu_temperature") {
SEC_OPEN_MAP("cpu_temperature");
print_cpu_temperature_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
SEC_CLOSE_MAP;
}
CASE_SEC("cpu_usage")
print_cpu_usage(cfg_getstr(sec, "format"));
CASE_SEC("cpu_usage") {
SEC_OPEN_MAP("cpu_usage");
print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"));
SEC_CLOSE_MAP;
}
}
if (output_format == O_I3BAR)
printf("],");
if (output_format == O_I3BAR) {
yajl_gen_array_close(json_gen);
const unsigned char *buf;
size_t len;
yajl_gen_get_buf(json_gen, &buf, &len);
write(STDOUT_FILENO, buf, len);
yajl_gen_clear(json_gen);
}
printf("\n");
fflush(stdout);

View File

@ -6,6 +6,9 @@ enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_NONE } output_format;
#include <stdbool.h>
#include <confuse.h>
#include <time.h>
#include <yajl/yajl_gen.h>
#include <unistd.h>
#include <string.h>
#define BEGINS_WITH(haystack, needle) (strncmp(haystack, needle, strlen(needle)) == 0)
#define max(a, b) ((a) > (b) ? (a) : (b))
@ -47,6 +50,65 @@ enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_NONE } output_format;
with(cfg_t *, sec, cfg_gettsec(cfg, name, title)) \
if (sec != NULL)
/* Macro which any plugin can use to output the full_text part (when the output
* format is JSON) or just output to stdout (any other output format). */
#define OUTPUT_FULL_TEXT(text) \
do { \
/* Terminate the output buffer here in any case, so that its \
* not forgotten in the module */ \
*outwalk = '\0'; \
if (output_format == O_I3BAR) { \
yajl_gen_string(json_gen, (const unsigned char *)"full_text", strlen("full_text")); \
yajl_gen_string(json_gen, (const unsigned char *)text, strlen(text)); \
} else { \
write(STDOUT_FILENO, text, strlen(text)); \
} \
} while (0)
#define SEC_OPEN_MAP(name) \
do { \
if (output_format == O_I3BAR) { \
yajl_gen_map_open(json_gen); \
yajl_gen_string(json_gen, (const unsigned char *)"name", strlen("name")); \
yajl_gen_string(json_gen, (const unsigned char *)name, strlen(name)); \
} \
} while (0)
#define SEC_CLOSE_MAP \
do { \
if (output_format == O_I3BAR) { \
yajl_gen_map_close(json_gen); \
} \
} while (0)
#define START_COLOR(colorstr) \
do { \
if (cfg_getbool(cfg_general, "colors")) { \
const char *val = cfg_getstr(cfg_general, colorstr); \
if (output_format == O_I3BAR) { \
yajl_gen_string(json_gen, (const unsigned char *)"color", strlen("color")); \
yajl_gen_string(json_gen, (const unsigned char *)val, strlen(val)); \
} else { \
outwalk += sprintf(outwalk, "%s", color("color_bad")); \
} \
} \
} while (0)
#define END_COLOR \
do { \
if (cfg_getbool(cfg_general, "colors") && output_format != O_I3BAR) { \
outwalk += sprintf(outwalk, "%s", endcolor()); \
} \
} while (0)
#define INSTANCE(instance) \
do { \
if (output_format == O_I3BAR) { \
yajl_gen_string(json_gen, (const unsigned char *)"instance", strlen("instance")); \
yajl_gen_string(json_gen, (const unsigned char *)instance, strlen(instance)); \
} \
} while (0)
typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
@ -63,19 +125,19 @@ char *endcolor() __attribute__ ((pure));
/* src/auto_detect_format.c */
char *auto_detect_format();
void print_ipv6_info(const char *format_up, const char *format_down);
void print_disk_info(const char *path, const char *format);
void print_battery_info(int number, const char *path, const char *format, bool last_full_capacity);
void print_time(const char *format, struct tm *current_tm);
void print_ddate(const char *format, struct tm *current_tm);
void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down);
void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format);
void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, bool last_full_capacity);
void print_time(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm);
void print_ddate(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm);
const char *get_ip_addr();
void print_wireless_info(const char *interface, const char *format_up, const char *format_down);
void print_run_watch(const char *title, const char *pidfile, const char *format);
void print_cpu_temperature_info(int zone, const char *path, const char *format);
void print_cpu_usage(const char *format);
void print_eth_info(const char *interface, const char *format_up, const char *format_down);
void print_load();
void print_volume(const char *fmt, const char *device, const char *mixer, int mixer_idx);
void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format);
void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format);
void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format);
void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
void print_load(yajl_gen json_gen, char *buffer, const char *format);
void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *device, const char *mixer, int mixer_idx);
bool process_runs(const char *path);
/* socket file descriptor for general purposes */

View File

@ -24,8 +24,6 @@ char *color(const char *colorstr) {
(void)snprintf(colorbuf, sizeof(colorbuf), "^fg(%s)", cfg_getstr(cfg_general, colorstr));
else if (output_format == O_XMOBAR)
(void)snprintf(colorbuf, sizeof(colorbuf), "<fc=%s>", cfg_getstr(cfg_general, colorstr));
else if (output_format == O_I3BAR)
(void)snprintf(colorbuf, sizeof(colorbuf), "\"color\":\"%s\", ", cfg_getstr(cfg_general, colorstr));
return colorbuf;
}
@ -45,8 +43,6 @@ void print_seperator() {
printf("^fg(%s)^p(5;-2)^ro(2)^p()^fg()^p(5)", cfg_getstr(cfg_general, "color_separator"));
else if (output_format == O_XMOBAR)
printf("<fc=%s> | </fc>", cfg_getstr(cfg_general, "color_separator"));
else if (output_format == O_I3BAR)
printf(", ");
else if (output_format == O_NONE)
printf(" | ");
}

View File

@ -3,6 +3,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
@ -17,7 +18,7 @@
* worn off your battery is.
*
*/
void print_battery_info(int number, const char *path, const char *format, bool last_full_capacity) {
void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, bool last_full_capacity) {
time_t empty_time;
struct tm *empty_tm;
char buf[1024];
@ -26,6 +27,7 @@ void print_battery_info(int number, const char *path, const char *format, bool l
char remainingbuf[256];
char emptytimebuf[256];
const char *walk, *last;
char *outwalk = buffer;
int full_design = -1,
remaining = -1,
present_rate = -1;
@ -36,14 +38,13 @@ void print_battery_info(int number, const char *path, const char *format, bool l
memset(remainingbuf, '\0', sizeof(remainingbuf));
memset(emptytimebuf, '\0', sizeof(emptytimebuf));
if (output_format == O_I3BAR)
printf("{\"name\":\"battery\", \"instance\": \"%s\", \"full_text\":\"", path);
INSTANCE(path);
#if defined(LINUX)
static char batpath[512];
sprintf(batpath, path, number);
if (!slurp(batpath, buf, sizeof(buf))) {
printf("No battery");
OUTPUT_FULL_TEXT("No battery");
return;
}
@ -170,25 +171,24 @@ void print_battery_info(int number, const char *path, const char *format, bool l
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (strncmp(walk+1, "status", strlen("status")) == 0) {
printf("%s", statusbuf);
outwalk += sprintf(outwalk, "%s", statusbuf);
walk += strlen("status");
} else if (strncmp(walk+1, "percentage", strlen("percentage")) == 0) {
printf("%s", percentagebuf);
outwalk += sprintf(outwalk, "%s", percentagebuf);
walk += strlen("percentage");
} else if (strncmp(walk+1, "remaining", strlen("remaining")) == 0) {
printf("%s", remainingbuf);
outwalk += sprintf(outwalk, "%s", remainingbuf);
walk += strlen("remaining");
} else if (strncmp(walk+1, "emptytime", strlen("emptytime")) == 0) {
printf("%s", emptytimebuf);
outwalk += sprintf(outwalk, "%s", emptytimebuf);
walk += strlen("emptytime");
}
}
if (output_format == O_I3BAR)
printf("\"}");
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -3,6 +3,7 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
@ -21,9 +22,10 @@ static char *thermal_zone;
* returns the temperature in degree celcius.
*
*/
void print_cpu_temperature_info(int zone, const char *path, const char *format) {
void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format) {
#ifdef THERMAL_ZONE
const char *walk;
char *outwalk = buffer;
static char buf[16];
if (path == NULL) {
@ -31,12 +33,11 @@ void print_cpu_temperature_info(int zone, const char *path, const char *format)
path = thermal_zone;
}
if (output_format == O_I3BAR)
printf("{\"name\":\"cpu_temperature\", \"instance\": \"%s\", \"full_text\":\"", path);
INSTANCE(path);
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
@ -47,24 +48,22 @@ void print_cpu_temperature_info(int zone, const char *path, const char *format)
goto error;
temp = strtol(buf, NULL, 10);
if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
(void)printf("?");
*(outwalk++) = '?';
else
(void)printf("%ld", (temp/1000));
outwalk += sprintf(outwalk, "%ld", (temp/1000));
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
int sysctl_rslt;
size_t sysctl_size = sizeof(sysctl_rslt);
if (sysctlbyname(path, &sysctl_rslt, &sysctl_size, NULL, 0))
goto error;
(void)printf("%d.%d", TZ_KELVTOC(sysctl_rslt));
outwalk += sprintf(outwalk, "%d.%d", TZ_KELVTOC(sysctl_rslt));
#endif
walk += strlen("degrees");
}
}
if (output_format == O_I3BAR)
printf("\"}");
OUTPUT_FULL_TEXT(buffer);
return;
error:
#endif

View File

@ -3,6 +3,7 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#ifdef __FreeBSD__
#include <sys/types.h>
@ -20,15 +21,13 @@ static int prev_idle = 0;
* percentage.
*
*/
void print_cpu_usage(const char *format) {
void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format) {
const char *walk;
char *outwalk = buffer;
char buf[1024];
int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total;
int diff_idle, diff_total, diff_usage;
if (output_format == O_I3BAR)
printf("{\"name\":\"cpu_usage\", \"full_text\":\"");
#if defined(LINUX)
static char statpath[512];
strcpy(statpath, "/proc/stat");
@ -64,19 +63,17 @@ void print_cpu_usage(const char *format) {
#endif
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (strncmp(walk+1, "usage", strlen("usage")) == 0) {
printf("%02d%%", diff_usage);
outwalk += sprintf(outwalk, "%02d%%", diff_usage);
walk += strlen("usage");
}
}
if (output_format == O_I3BAR)
printf("\"}");
OUTPUT_FULL_TEXT(buffer);
return;
error:
(void)fputs("Cannot read usage\n", stderr);

View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
@ -62,76 +63,77 @@ struct disc_time {
};
/* Print the date *dt in format *format */
int format_output(char *format, struct disc_time *dt) {
static int format_output(char *outwalk, char *format, struct disc_time *dt) {
char *orig_outwalk = outwalk;
char *i;
char *tibs_end = 0;
for (i = format; *i != '\0'; i++) {
if (*i != '%') {
putchar(*i);
*(outwalk++) = *i;
continue;
}
switch (*(i+1)) {
/* Weekday in long and abbreviation */
case 'A':
printf("%s", day_long[dt->week_day]);
outwalk += sprintf(outwalk, "%s", day_long[dt->week_day]);
break;
case 'a':
printf("%s", day_short[dt->week_day]);
outwalk += sprintf(outwalk, "%s", day_short[dt->week_day]);
break;
/* Season in long and abbreviation */
case 'B':
printf("%s", season_long[dt->season]);
outwalk += sprintf(outwalk, "%s", season_long[dt->season]);
break;
case 'b':
printf("%s", season_short[dt->season]);
outwalk += sprintf(outwalk, "%s", season_short[dt->season]);
break;
/* Day of the season (ordinal and cardinal) */
case 'd':
printf("%d", dt->season_day + 1);
outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
break;
case 'e':
printf("%d", dt->season_day + 1);
outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
switch (dt->season_day) {
case 0:
printf("st");
outwalk += sprintf(outwalk, "st");
break;
case 1:
printf("nd");
outwalk += sprintf(outwalk, "nd");
break;
case 2:
printf("rd");
outwalk += sprintf(outwalk, "rd");
break;
default:
printf("th");
outwalk += sprintf(outwalk, "th");
break;
}
break;
/* YOLD */
case 'Y':
printf("%d", dt->year);
outwalk += sprintf(outwalk, "%d", dt->year);
break;
/* Holidays */
case 'H':
if (dt->season_day == 4) {
printf(holidays[dt->season]);
outwalk += sprintf(outwalk, holidays[dt->season]);
}
if (dt->season_day == 49) {
printf(holidays[dt->season + 5]);
outwalk += sprintf(outwalk, holidays[dt->season + 5]);
}
break;
/* Stop parsing the format string, except on Holidays */
case 'N':
if (dt->season_day != 4 && dt->season_day != 49) {
return 0;
return (outwalk - orig_outwalk);
}
break;
/* Newline- and Tabbing-characters */
case 'n':
printf("\n");
outwalk += sprintf(outwalk, "\n");
break;
case 't':
printf("\t");
outwalk += sprintf(outwalk, "\t");
break;
/* The St. Tib's Day replacement */
case '{':
@ -142,11 +144,11 @@ int format_output(char *format, struct disc_time *dt) {
}
if (dt->st_tibs_day) {
/* We outpt "St. Tib's Day... */
printf("St. Tib's Day");
outwalk += sprintf(outwalk, "St. Tib's Day");
} else {
/* ...or parse the substring between %{ and %} ... */
*tibs_end = '\0';
if (!format_output(i + 2, dt)) return 0;
outwalk += format_output(outwalk, i + 2, dt);
*tibs_end = '%';
}
/* ...and continue with the rest */
@ -157,12 +159,12 @@ int format_output(char *format, struct disc_time *dt) {
break;
default:
/* No escape-sequence, so we just skip */
printf("%%%c",*(i+1));
outwalk += sprintf(outwalk, "%%%c", *(i+1));
break;
}
i++;
}
return 1;
return (outwalk - orig_outwalk);
}
/* Get the current date and convert it to discordian */
@ -194,7 +196,8 @@ struct disc_time *get_ddate(struct tm *current_tm) {
return &dt;
}
void print_ddate(const char *format, struct tm *current_tm) {
void print_ddate(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm) {
char *outwalk = buffer;
static char *form = NULL;
struct disc_time *dt;
if ((dt = get_ddate(current_tm)) == NULL)
@ -202,10 +205,7 @@ void print_ddate(const char *format, struct tm *current_tm) {
if (form == NULL)
if ((form = malloc(strlen(format) + 1)) == NULL)
return;
if (output_format == O_I3BAR)
printf("{\"name\":\"ddate\", \"full_text\":\"");
strcpy(form, format);
format_output(form, dt);
if (output_format == O_I3BAR)
printf("\"}");
outwalk += format_output(outwalk, form, dt);
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -10,7 +10,7 @@
#include <sys/param.h>
#include <sys/mount.h>
#endif
#include <yajl/yajl_gen.h>
#include "i3status.h"
@ -23,17 +23,17 @@
* Prints the given amount of bytes in a human readable manner.
*
*/
static void print_bytes_human(uint64_t bytes) {
static int print_bytes_human(char *outwalk, uint64_t bytes) {
if (bytes > TERABYTE)
printf("%.02f TB", (double)bytes / TERABYTE);
return sprintf(outwalk, "%.02f TB", (double)bytes / TERABYTE);
else if (bytes > GIGABYTE)
printf("%.01f GB", (double)bytes / GIGABYTE);
return sprintf(outwalk, "%.01f GB", (double)bytes / GIGABYTE);
else if (bytes > MEGABYTE)
printf("%.01f MB", (double)bytes / MEGABYTE);
return sprintf(outwalk, "%.01f MB", (double)bytes / MEGABYTE);
else if (bytes > KILOBYTE)
printf("%.01f KB", (double)bytes / KILOBYTE);
return sprintf(outwalk, "%.01f KB", (double)bytes / KILOBYTE);
else {
printf("%.01f B", (double)bytes);
return sprintf(outwalk, "%.01f B", (double)bytes);
}
}
@ -42,11 +42,11 @@ static void print_bytes_human(uint64_t bytes) {
* human readable manner.
*
*/
void print_disk_info(const char *path, const char *format) {
void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format) {
const char *walk;
char *outwalk = buffer;
if (output_format == O_I3BAR)
printf("{\"name\":\"disk_info\", \"instance\": \"%s\", \"full_text\":\"", path);
INSTANCE(path);
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
struct statfs buf;
@ -62,31 +62,31 @@ void print_disk_info(const char *path, const char *format) {
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk+1, "free")) {
print_bytes_human((uint64_t)buf.f_bsize * (uint64_t)buf.f_bfree);
outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bfree);
walk += strlen("free");
}
if (BEGINS_WITH(walk+1, "used")) {
print_bytes_human((uint64_t)buf.f_bsize * ((uint64_t)buf.f_blocks - (uint64_t)buf.f_bfree));
outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * ((uint64_t)buf.f_blocks - (uint64_t)buf.f_bfree));
walk += strlen("used");
}
if (BEGINS_WITH(walk+1, "total")) {
print_bytes_human((uint64_t)buf.f_bsize * (uint64_t)buf.f_blocks);
outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_blocks);
walk += strlen("total");
}
if (BEGINS_WITH(walk+1, "avail")) {
print_bytes_human((uint64_t)buf.f_bsize * (uint64_t)buf.f_bavail);
outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bavail);
walk += strlen("avail");
}
}
if (output_format == O_I3BAR)
printf("\"}");
*outwalk = '\0';
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -26,7 +26,7 @@
#endif
static void print_eth_speed(const char *interface) {
static int print_eth_speed(char *outwalk, const char *interface) {
#if defined(LINUX)
int ethspeed = 0;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@ -44,8 +44,8 @@ static void print_eth_speed(const char *interface) {
(void)strcpy(ifr.ifr_name, interface);
if (ioctl(general_socket, SIOCETHTOOL, &ifr) == 0) {
ethspeed = (ecmd.speed == USHRT_MAX ? 0 : ecmd.speed);
printf("%d Mbit/s", ethspeed);
} else printf("?");
return sprintf(outwalk, "%d Mbit/s", ethspeed);
} else return sprintf(outwalk, "?");
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
struct ifmediareq ifm;
(void)memset(&ifm, 0, sizeof(ifm));
@ -66,7 +66,7 @@ static void print_eth_speed(const char *interface) {
break;
}
ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
printf("%s", ethspeed);
return sprintf(outwalk, "%s", ethspeed);
#endif
}
@ -74,42 +74,37 @@ static void print_eth_speed(const char *interface) {
* Combines ethernet IP addresses and speed (if requested) for displaying
*
*/
void print_eth_info(const char *interface, const char *format_up, const char *format_down) {
void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
const char *walk;
const char *ip_address = get_ip_addr(interface);
char *outwalk = buffer;
if (output_format == O_I3BAR)
printf("{\"name\":\"ethernet\", \"instance\": \"%s\", ", interface);
INSTANCE(interface);
if (ip_address == NULL) {
printf("%s", color("color_bad"));
printf("%s", format_down);
(void)printf("%s", endcolor());
return;
} else {
printf("%s", color("color_good"));
START_COLOR("color_bad");
outwalk += sprintf(outwalk, "%s", format_down);
goto out;
}
if (output_format == O_I3BAR)
printf("\"full_text\":\"");
START_COLOR("color_good");
for (walk = format_up; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
printf("%s", ip_address);
outwalk += sprintf(outwalk, "%s", ip_address);
walk += strlen("ip");
} else if (strncmp(walk+1, "speed", strlen("speed")) == 0) {
print_eth_speed(interface);
outwalk += print_eth_speed(outwalk, interface);
walk += strlen("speed");
}
}
(void)printf("%s", endcolor());
if (output_format == O_I3BAR)
printf("\"}");
out:
END_COLOR;
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -29,8 +29,6 @@ const char *get_ip_addr(const char *interface) {
if (ifaddr == NULL)
return NULL;
addrp = ifaddr;
/* Skip until we are at the AF_INET address of interface */
for (addrp = ifaddr;

View File

@ -8,6 +8,7 @@
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
@ -109,30 +110,27 @@ static char *get_ipv6_addr() {
return NULL;
}
void print_ipv6_info(const char *format_up, const char *format_down) {
void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down) {
const char *walk;
char *addr_string = get_ipv6_addr();
if (output_format == O_I3BAR)
printf("{\"name\":\"ipv6\", \"full_text\":\"");
char *outwalk = buffer;
if (addr_string == NULL) {
printf("%s", format_down);
OUTPUT_FULL_TEXT(format_down);
return;
}
for (walk = format_up; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
printf("%s", addr_string);
outwalk += sprintf(outwalk, "%s", addr_string);
walk += strlen("ip");
}
}
if (output_format == O_I3BAR)
printf("\"}");
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -3,11 +3,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <yajl/yajl_gen.h>
void print_load(const char *format) {
/* Get load */
if (output_format == O_I3BAR)
printf("{\"name\":\"load\", \"full_text\":\"");
void print_load(yajl_gen json_gen, char *buffer, const char *format) {
char *outwalk = buffer;
/* Get load */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(sun)
double loadavg[3];
@ -18,28 +18,28 @@ void print_load(const char *format) {
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk+1, "1min")) {
(void)printf("%1.2f", loadavg[0]);
outwalk += sprintf(outwalk, "%1.2f", loadavg[0]);
walk += strlen("1min");
}
if (BEGINS_WITH(walk+1, "5min")) {
(void)printf("%1.2f", loadavg[1]);
outwalk += sprintf(outwalk, "%1.2f", loadavg[1]);
walk += strlen("5min");
}
if (BEGINS_WITH(walk+1, "15min")) {
(void)printf("%1.2f", loadavg[2]);
outwalk += sprintf(outwalk, "%1.2f", loadavg[2]);
walk += strlen("15min");
}
}
if (output_format == O_I3BAR)
printf("\"}");
*outwalk = '\0';
OUTPUT_FULL_TEXT(buffer);
return;
error:

View File

@ -1,36 +1,32 @@
#include <stdio.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
void print_run_watch(const char *title, const char *pidfile, const char *format) {
void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format) {
bool running = process_runs(pidfile);
const char *walk;
char *outwalk = buffer;
if (output_format == O_I3BAR)
printf("{\"name\":\"run_watch\", \"instance\": \"%s\", ", pidfile);
INSTANCE(pidfile);
printf("%s", (running ? color("color_good") : color("color_bad")));
if (output_format == O_I3BAR)
printf("\"full_text\":\"");
START_COLOR((running ? "color_good" : "color_bad"));
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (strncmp(walk+1, "title", strlen("title")) == 0) {
printf("%s", title);
outwalk += sprintf(outwalk, "%s", title);
walk += strlen("title");
} else if (strncmp(walk+1, "status", strlen("status")) == 0) {
printf("%s", (running ? "yes" : "no"));
outwalk += sprintf(outwalk, "%s", (running ? "yes" : "no"));
walk += strlen("status");
}
}
printf("%s", endcolor());
if (output_format == O_I3BAR)
printf("\"}");
END_COLOR;
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -2,19 +2,16 @@
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <yajl/yajl_gen.h>
#include "i3status.h"
void print_time(const char *format, struct tm *current_tm) {
static char part[512];
/* Get date & time */
if (current_tm == NULL) {
void print_time(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm) {
char *outwalk = buffer;
if (current_tm == NULL)
return;
}
if (output_format == O_I3BAR)
printf("{\"name\":\"time\", \"full_text\":\"");
(void)strftime(part, sizeof(part), format, current_tm);
printf("%s", part);
if (output_format == O_I3BAR)
printf("\"}");
/* Get date & time */
outwalk += strftime(outwalk, 4095, format, current_tm);
*outwalk = '\0';
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -41,10 +41,16 @@ static void free_hdl(struct mixer_hdl *hdl) {
}
#endif
void print_volume(const char *fmt, const char *device, const char *mixer, int mixer_idx) {
/* Printing volume only works with ALSA at the moment */
if (output_format == O_I3BAR)
printf("{\"name\":\"volume\", \"instance\": \"%s.%s.%d\", \"full_text\":\"", device, mixer, mixer_idx);
void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *device, const char *mixer, int mixer_idx) {
char *outwalk = buffer;
/* Printing volume only works with ALSA at the moment */
if (output_format == O_I3BAR) {
char *instance;
asprintf(&instance, "%s.%s.%d", device, mixer, mixer_idx);
INSTANCE(instance);
free(instance);
}
#ifdef LINUX
/* Check if we already opened the mixer and get the handle
* from cache if so */
@ -149,11 +155,11 @@ void print_volume(const char *fmt, const char *device, const char *mixer, int mi
const char *walk = fmt;
for (; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk+1, "volume")) {
printf("%d%%", avg);
outwalk += sprintf(outwalk, "%d%%", avg);
walk += strlen("volume");
}
}
@ -172,16 +178,17 @@ void print_volume(const char *fmt, const char *device, const char *mixer, int mi
const char *walk = fmt;
for (; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk+1, "volume")) {
printf("%d%%", vol & 0x7f);
outwalk += sprintf(outwalk, "%d%%", vol & 0x7f);
walk += strlen("volume");
}
}
close(mixfd);
#endif
if (output_format == O_I3BAR)
printf("\"}");
*outwalk = '\0';
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -221,40 +221,37 @@ static int get_wireless_info(const char *interface, wireless_info_t *info) {
return 0;
}
void print_wireless_info(const char *interface, const char *format_up, const char *format_down) {
void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
const char *walk;
char *outwalk = buffer;
wireless_info_t info;
if (output_format == O_I3BAR)
printf("{\"name\":\"wireless\", \"instance\": \"%s\", ", interface);
INSTANCE(interface);
if (get_wireless_info(interface, &info)) {
walk = format_up;
if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
printf("%s", info.quality < info.quality_average ? color("color_degraded") : color("color_good"));
START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
}
else {
walk = format_down;
printf("%s", color("color_bad"));
START_COLOR("color_bad");
}
if (output_format == O_I3BAR)
printf("\"full_text\":\"");
for (; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk+1, "quality")) {
if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
if (info.quality_max)
printf("%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
else
printf("%d", info.quality);
}
else {
printf("no value");
outwalk += sprintf(outwalk, "%d", info.quality);
} else {
*(outwalk++) = '?';
}
walk += strlen("quality");
}
@ -262,12 +259,11 @@ void print_wireless_info(const char *interface, const char *format_up, const cha
if (BEGINS_WITH(walk+1, "signal")) {
if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
if (info.signal_level_max)
printf("%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
else
printf("%d dBm", info.signal_level);
}
else {
printf("no value");
outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
} else {
*(outwalk++) = '?';
}
walk += strlen("signal");
}
@ -275,46 +271,41 @@ void print_wireless_info(const char *interface, const char *format_up, const cha
if (BEGINS_WITH(walk+1, "noise")) {
if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
if (info.noise_level_max)
printf("%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
else
printf("%d dBm", info.noise_level);
}
else {
printf("no value");
outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
} else {
*(outwalk++) = '?';
}
walk += strlen("noise");
}
if (BEGINS_WITH(walk+1, "essid")) {
if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
printf("%s", info.essid);
outwalk += sprintf(outwalk, "%s", info.essid);
else
printf("no value");
*(outwalk++) = '?';
walk += strlen("essid");
}
if (BEGINS_WITH(walk+1, "ip")) {
const char *ip_address = get_ip_addr(interface);
if (ip_address != NULL)
(void)printf("%s", get_ip_addr(interface));
else (void)printf("no IP");
outwalk += sprintf(outwalk, "%s", (ip_address ? ip_address : "no IP"));
walk += strlen("ip");
}
#ifdef LINUX
if (BEGINS_WITH(walk+1, "bitrate")) {
char buffer[128];
char br_buffer[128];
iw_print_bitrate(buffer, sizeof(buffer), info.bitrate);
iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
printf("%s", buffer);
outwalk += sprintf(outwalk, "%s", br_buffer);
walk += strlen("bitrate");
}
#endif
}
(void)printf("%s", endcolor());
if (output_format == O_I3BAR)
printf("\"}");
END_COLOR;
OUTPUT_FULL_TEXT(buffer);
}