tmisu

Notification to stdout daemon
git clone https://git.inz.fi/tmisu/
Log | Files | Refs | README | LICENSE

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