]> git.sur5r.net Git - i3/i3status/commitdiff
Properly output JSON with libyajl
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 25 Mar 2012 18:55:55 +0000 (20:55 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 25 Mar 2012 20:05:00 +0000 (22:05 +0200)
18 files changed:
Makefile
debian/control
i3status.c
include/i3status.h
src/output.c
src/print_battery_info.c
src/print_cpu_temperature.c
src/print_cpu_usage.c
src/print_ddate.c
src/print_disk_info.c
src/print_eth_info.c
src/print_ip_addr.c
src/print_ipv6_addr.c
src/print_load.c
src/print_run_watch.c
src/print_time.c
src/print_volume.c
src/print_wireless_info.c

index 0cd1c56d20422f720df558c7ba1ea74fd74dee3b..da42640ea70c27c54158ffa885ba4a468c46e2ad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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))"
index 61d286d47d4c99ee28af6b26997df93952a8cf76..37615aa8b8d0633b867ed01c369cce74113af518 100644 (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
 
index b7f9b86a6037b1081289849eb713dbde15303cc5..b2b1714508cddacd792ed82a8947d0a6aec4638e 100644 (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 it’s 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_TITLE("wireless")
-                                print_wireless_info(title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
-
-                        CASE_SEC_TITLE("ethernet")
-                                print_eth_info(title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
-
-                        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("run_watch")
-                                print_run_watch(title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
-
-                        CASE_SEC_TITLE("disk")
-                                print_disk_info(title, cfg_getstr(sec, "format"));
-
-                        CASE_SEC("load")
-                                print_load(cfg_getstr(sec, "format"));
-
-                        CASE_SEC("time")
-                                print_time(cfg_getstr(sec, "format"), current_tm);
-
-                        CASE_SEC("ddate")
-                                print_ddate(cfg_getstr(sec, "format"), current_tm);
-
-                        CASE_SEC_TITLE("volume")
-                                print_volume(cfg_getstr(sec, "format"),
+                        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") {
+                                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") {
+                                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") {
+                                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") {
+                                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") {
+                                SEC_OPEN_MAP("disk_info");
+                                print_disk_info(json_gen, buffer, title, cfg_getstr(sec, "format"));
+                                SEC_CLOSE_MAP;
+                        }
+
+                        CASE_SEC("load") {
+                                SEC_OPEN_MAP("load");
+                                print_load(json_gen, buffer, cfg_getstr(sec, "format"));
+                                SEC_CLOSE_MAP;
+                        }
+
+                        CASE_SEC("time") {
+                                SEC_OPEN_MAP("time");
+                                print_time(json_gen, buffer, cfg_getstr(sec, "format"), current_tm);
+                                SEC_CLOSE_MAP;
+                        }
+
+                        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") {
+                                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"));
-
-                        CASE_SEC_TITLE("cpu_temperature")
-                                print_cpu_temperature_info(atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
-
-                        CASE_SEC("cpu_usage")
-                                print_cpu_usage(cfg_getstr(sec, "format"));
+                                SEC_CLOSE_MAP;
+                        }
+
+                        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") {
+                                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);
 
index e40003ca7f4987b1b7ac85f5bd04e2a278918e06..4ec0ce429807db0cd35dc1b11bd5e4b9405ee18e 100644 (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 it’s \
+                * 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 */
index 96dd3e498073ffe6286d5ce4b194ceb6046671b6..c0c1480bcbed785bf6f0ee03ac9327379df7b9a4 100644 (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(" | ");
 }
index 10137c2f4248d5629165734ecd98917b463b5bde..3892d359a187b7e1f1871bf184dcfbae3ef7e991 100644 (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);
 }
index 08fac88cd3ade54ddce7c846fbcbb58f8e628ac0..65fcfae6ae3d8094ee153362d97c04404fdf18d1 100644 (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
index d97a7fa303a3c50bcf2226633ffaafa5cb4644c8..24afca7166a95e74c4b6e9030f3a136ba3eb8fc3 100644 (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);
index 0401a3f366d22c177fd9daf3ee88d4b1a98877b3..ca3ab0efa0ceb283390e3b63e8a68e54005df6e2 100644 (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);
 }
index 1ac22d0f3a51d453f9c70f17b1c19a93a3e95197..7235325b926f24aad988014a6f9cdddbfd840a52 100644 (file)
@@ -10,7 +10,7 @@
 #include <sys/param.h>
 #include <sys/mount.h>
 #endif
-
+#include <yajl/yajl_gen.h>
 
 #include "i3status.h"
 
  * 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);
 }
index 4fae191293994005cc7223fe23c3942d91cb6cfd..1e877c09be710b742f485267f551bad7e76a299d 100644 (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);
 }
index 1c2839da4689219761686da149574f227cf80bcc..e97edaab489e5112a5ffdae2775a486fb7693c97 100644 (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;
 
index 3ace6a24fe20c0856e22ad7c88802de246a6bbfc..3f1c81d60ef49d0178bf03e969bebe834228d97e 100644 (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);
 }
index 8c2343bcfe395b3b65666cea8a0d0b7ba3eb2037..181773b0e324d62d206251a777dc810c53685340 100644 (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:
index c806d8e25c04d74a0e630db400d79ee4b06a16bc..f93c3a0e02c3d086c1de3c906bdc993ae31fb87f 100644 (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);
 }
index 3c48d3f8e5a1188ffeb20db90aca17c88d32a81a..a1bb34cdf3e089d0a4fef62cd0c3bea05b274910 100644 (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);
 }
index 85b6176de03267b2f0e66df64aa76bf8ab7768ad..5c34c3e6d16e0e5ef72b5bc7c5e91ec9381550a3 100644 (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);
 }
index 530d9cf8eb3c2533e107458cc1d1de5229c63ad1..642dece5acea7384c90e17e7709cbd7ec8951ba0 100644 (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);
 }