output.c (3848B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <inttypes.h> 4 #include <string.h> 5 6 #include "output.h" 7 #include "tmisu.h" 8 9 static void escputs(const char *string, const char *escape) 10 { 11 static const char *special = "\b\f\n\r\t"; 12 static const char *sp_rep = "bfnrt"; 13 char esc[2] = "\\"; 14 15 while (*string) { 16 size_t len = strcspn(string, escape); 17 fwrite(string, 1, len, stdout); 18 string += len; 19 20 while (*string && strchr(escape, *string)) { 21 const char *sp; 22 if ((sp = strchr(special, *string))) 23 esc[1] = sp_rep[sp - special]; 24 else 25 esc[1] = *string; 26 string++; 27 fwrite(esc, 1, 2, stdout); 28 } 29 } 30 } 31 32 void esc_printf(const char *spec, const char *fmt, ...) 33 { 34 const char *arg; 35 DBusBasicValue value; 36 va_list a; 37 va_start(a, fmt); 38 39 while (*fmt) { 40 size_t n = strcspn(fmt, "%"); 41 fwrite(fmt, 1, n, stdout); 42 if (!fmt[n]) 43 break; 44 switch (fmt[n + 1]) { 45 case 's': 46 arg = va_arg(a, const char *); 47 fputs(arg, stdout); 48 break; 49 case 'z': 50 arg = va_arg(a, const char *); 51 escputs(arg, spec); 52 break; 53 case 'D': 54 DBusMessageIter *i = va_arg(a, DBusMessageIter *); 55 int type = dbus_message_iter_get_arg_type(i); 56 57 if (type == DBUS_TYPE_ARRAY || 58 type == DBUS_TYPE_STRUCT) { 59 fputs("null", stdout); 60 break; 61 } 62 63 dbus_message_iter_get_basic(i, &value); 64 switch (type) { 65 case DBUS_TYPE_BYTE: 66 printf("%" PRIu8, value.byt); 67 break; 68 case DBUS_TYPE_BOOLEAN: 69 printf("%s", value.bool_val ? "true" : "false"); 70 break; 71 case DBUS_TYPE_INT16: 72 printf("%" PRId16, value.i16); 73 break; 74 case DBUS_TYPE_UINT16: 75 printf("%" PRIu16, value.u16); 76 break; 77 case DBUS_TYPE_INT32: 78 printf("%" PRId32, value.i32); 79 break; 80 case DBUS_TYPE_UINT32: 81 printf("%" PRIu32, value.u32); 82 break; 83 case DBUS_TYPE_INT64: 84 printf("%" PRId64, value.i64); 85 break; 86 case DBUS_TYPE_UINT64: 87 printf("%" PRIu64, value.u64); 88 break; 89 case DBUS_TYPE_DOUBLE: 90 printf("%lf", value.dbl); 91 break; 92 case DBUS_TYPE_STRING: 93 case DBUS_TYPE_OBJECT_PATH: 94 fwrite("\"", 1, 1, stdout); 95 escputs(value.str, spec); 96 fwrite("\"", 1, 1, stdout); 97 break; 98 } 99 break; 100 case '%': 101 fputs("%", stdout); 102 break; 103 } 104 fmt += n + 2; 105 } 106 } 107 108 static void json_output(uint32_t id, struct notification_data *d, 109 const char *delimiter) 110 { 111 DBusMessageIter i; 112 const char *sep = ""; 113 const char *json_spec = "\\\n\r\b\f\""; 114 printf("{" 115 "\"id\": %" PRIu32 ", ", id); 116 if (d->app_name) 117 esc_printf(json_spec, "\"app_name\": \"%s\", ", d->app_name); 118 if (d->icon) 119 esc_printf(json_spec, "\"app_icon\": \"%s\", ", d->icon); 120 printf("\"replaces_id\": %" PRIu32 ", " 121 "\"timeout\": %" PRId32 ", ", 122 d->replaces, d->expiry_ms); 123 124 printf("\"hints\": {"); 125 for (i = d->hints; 126 dbus_message_iter_get_arg_type(&i) != DBUS_TYPE_INVALID; 127 dbus_message_iter_next(&i)) { 128 DBusMessageIter di; 129 const char *key; 130 131 dbus_message_iter_recurse(&i, &di); 132 dbus_message_iter_get_basic(&di, &key); 133 dbus_message_iter_next(&di); 134 dbus_message_iter_recurse(&di, &di); 135 136 esc_printf(json_spec, "%s\"%z\": %D", sep, key, &di); 137 sep = ", "; 138 } 139 printf("}, \"actions\": {"); 140 141 sep = ""; 142 for (i = d->actions; 143 dbus_message_iter_get_arg_type(&i) == DBUS_TYPE_STRING; 144 dbus_message_iter_next(&i)) { 145 const char *key; 146 const char *value; 147 148 if (!dbus_message_iter_has_next(&i)) 149 break; 150 151 dbus_message_iter_get_basic(&i, &key); 152 dbus_message_iter_next(&i); 153 dbus_message_iter_get_basic(&i, &value); 154 155 esc_printf(json_spec, "%s\"%z\": \"%z\"", sep, key, value); 156 sep = ", "; 157 } 158 159 esc_printf(json_spec, 160 "}, " 161 "\"summary\": \"%z\", " 162 "\"body\": \"%z\"" 163 "}", d->summary, d->body, delimiter); 164 } 165 166 void output_notification(uint32_t id, struct notification_data *notif) 167 { 168 json_output(id, notif, ", "); 169 fflush(stdout); 170 } 171