commit 048f4a417cb321922ddd3377fc3e17c0706d305f
parent 5d8f9c1f832f856f3ca78bb27c82dd34dacc4e5d
Author: Santtu Lakkala <inz@inz.fi>
Date: Wed, 2 Mar 2022 16:06:31 +0200
Some rewrite
Diffstat:
A | arg.h | | | 37 | +++++++++++++++++++++++++++++++++++++ |
M | output.c | | | 305 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
M | output.h | | | 8 | ++++++-- |
M | tmisu.c | | | 112 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
4 files changed, 223 insertions(+), 239 deletions(-)
diff --git a/arg.h b/arg.h
@@ -0,0 +1,37 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H
+#define ARG_H
+
+extern char *argv0;
+
+/* int main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, *argv ? (argc--, argv++) : ((void *)0); \
+ *argv && (*argv)[0] == '-' && (*argv)[1]; argc--, argv++) { \
+ int i_, argused_; \
+ if ((*argv)[1] == '-' && !(*argv)[2]) { \
+ argc--, argv++; \
+ break; \
+ } \
+ for (i_ = 1, argused_ = 0; (*argv)[i_]; i_++) { \
+ switch((*argv)[i_])
+#define ARGEND if (argused_) { \
+ if ((*argv)[i_ + 1]) { \
+ break; \
+ } else { \
+ argc--, argv++; \
+ break; \
+ } \
+ } \
+ } \
+ }
+#define ARGC() ((*argv)[i_])
+#define ARGF_(x) (((*argv)[i_ + 1]) ? (argused_ = 1, &((*argv)[i_ + 1])) : \
+ (*(argv + 1)) ? (argused_ = 1, *(argv + 1)) : (x))
+#define EARGF(x) ARGF_(((x), exit(1), (char *)0))
+#define ARGF() ARGF_((char *)0)
+
+#endif
diff --git a/output.c b/output.c
@@ -6,227 +6,166 @@
#include "output.h"
#include "tmisu.h"
-static void print_sanitized(const char *string, const char *escape) {
+static void escputs(const char *string, const char *escape)
+{
+ static const char *special = "\b\f\n\r\t";
+ static const char *sp_rep = "bfnrt";
+ char esc[2] = "\\";
+
while (*string) {
size_t len = strcspn(string, escape);
- printf("%.*s", (int)len, string);
+ fwrite(string, 1, len, stdout);
string += len;
+
while (*string && strchr(escape, *string)) {
- if (*string == '\n')
- printf("\\n");
+ const char *sp;
+ if ((sp = strchr(special, *string)))
+ esc[1] = sp_rep[sp - special];
else
- printf("\\%c", *string);
+ esc[1] = *string;
string++;
+ fwrite(esc, 1, 2, stdout);
}
}
}
-static void hints_output_iterator(DBusMessageIter *hints, const char *key_prefix, const char *key_suffix, const char *str_prefix, const char *str_suffix, const char *escape, const char *delimiter, int join)
+void esc_printf(const char *spec, const char *fmt, ...)
{
- const char *d = "";
- for (; dbus_message_iter_get_arg_type(hints) != DBUS_TYPE_INVALID; dbus_message_iter_next(hints), d = delimiter) {
- DBusMessageIter dictentry;
- DBusMessageIter variant;
- DBusBasicValue value;
- const char *key;
-
- dbus_message_iter_recurse(hints, &dictentry);
- dbus_message_iter_get_basic(&dictentry, &key);
- dbus_message_iter_next(&dictentry);
- dbus_message_iter_recurse(&dictentry, &variant);
-
- printf("%s%s", d, key_prefix);
- print_sanitized(key, escape);
- printf("%s", key_suffix);
-
- if (!dbus_type_is_basic(dbus_message_iter_get_arg_type(&variant))) {
- printf("null");
- continue;
- }
-
- dbus_message_iter_get_basic(&variant, &value);
-
- switch (dbus_message_iter_get_arg_type(&variant)) {
- case DBUS_TYPE_BYTE:
- printf("%" PRIu8, value.byt);
+ const char *arg;
+ DBusBasicValue value;
+ va_list a;
+ va_start(a, fmt);
+
+ while (*fmt) {
+ size_t n = strcspn(fmt, "%");
+ fwrite(fmt, 1, n, stdout);
+ if (!fmt[n])
break;
- case DBUS_TYPE_BOOLEAN:
- printf("%s", value.bool_val ? "true" : "false");
+ switch (fmt[n + 1]) {
+ case 's':
+ arg = va_arg(a, const char *);
+ fputs(arg, stdout);
break;
- case DBUS_TYPE_INT16:
- printf("%" PRId16, value.i16);
+ case 'z':
+ arg = va_arg(a, const char *);
+ escputs(arg, spec);
break;
- case DBUS_TYPE_UINT16:
- printf("%" PRIu16, value.u16);
+ case 'D':
+ DBusMessageIter *i = va_arg(a, DBusMessageIter *);
+ int type = dbus_message_iter_get_arg_type(i);
+
+ if (type == DBUS_TYPE_ARRAY ||
+ type == DBUS_TYPE_STRUCT) {
+ fputs("null", stdout);
+ break;
+ }
+
+ dbus_message_iter_get_basic(i, &value);
+ switch (type) {
+ case DBUS_TYPE_BYTE:
+ printf("%" PRIu8, value.byt);
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ printf("%s", value.bool_val ? "true" : "false");
+ break;
+ case DBUS_TYPE_INT16:
+ printf("%" PRId16, value.i16);
+ break;
+ case DBUS_TYPE_UINT16:
+ printf("%" PRIu16, value.u16);
+ break;
+ case DBUS_TYPE_INT32:
+ printf("%" PRId32, value.i32);
+ break;
+ case DBUS_TYPE_UINT32:
+ printf("%" PRIu32, value.u32);
+ break;
+ case DBUS_TYPE_INT64:
+ printf("%" PRId64, value.i64);
+ break;
+ case DBUS_TYPE_UINT64:
+ printf("%" PRIu64, value.u64);
+ break;
+ case DBUS_TYPE_DOUBLE:
+ printf("%lf", value.dbl);
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ fwrite("\"", 1, 1, stdout);
+ escputs(value.str, spec);
+ fwrite("\"", 1, 1, stdout);
+ break;
+ }
break;
- case DBUS_TYPE_INT32:
- printf("%" PRId32, value.i32);
+ case '%':
+ fputs("%", stdout);
break;
- case DBUS_TYPE_UINT32:
- printf("%" PRIu32, value.u32);
- break;
- case DBUS_TYPE_INT64:
- printf("%" PRId64, value.i64);
- break;
- case DBUS_TYPE_UINT64:
- printf("%" PRIu64, value.u64);
- break;
- case DBUS_TYPE_DOUBLE:
- printf("%lf", value.dbl);
- break;
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- dbus_message_iter_get_basic(&variant, &value);
- printf("%s", str_prefix);
- print_sanitized(value.str, escape);
- printf("%s", str_suffix);
- continue;
- break;
- default:
- printf("null%s", d);
- continue;
}
+ fmt += n + 2;
}
-
- if (!join && d == delimiter)
- printf("%s", delimiter);
}
-static void default_output(const char *app_name, const char *app_icon, dbus_uint32_t id, dbus_uint32_t replaces_id,
- dbus_int32_t timeout, DBusMessageIter *hints, DBusMessageIter *actions, const char *summary,
- const char *body, const char *delimiter)
+static void json_output(uint32_t id, struct notification_data *d,
+ const char *delimiter)
{
- (void)id;
- printf("app_name: ");
- print_sanitized(app_name, "\n\\");
- printf("%sapp_icon: ", delimiter);
- print_sanitized(app_icon, "\n\\");
- printf("%sreplaces_id: %" PRIu32 "%stimeout: %" PRId32 "%s", delimiter,
- replaces_id, delimiter,
- timeout, delimiter);
-
- printf("hints:%s", delimiter);
- hints_output_iterator(hints, "\t", ": ", "", "", "\n\\", delimiter, 0);
-
- printf("actions:%s", delimiter);
- while (dbus_message_iter_get_arg_type(actions) != DBUS_TYPE_INVALID) {
- if (!dbus_message_iter_has_next(actions))
- break;
- const char *key;
- const char *value;
-
- dbus_message_iter_get_basic(actions, &key);
- dbus_message_iter_next(actions);
- dbus_message_iter_get_basic(actions, &value);
- dbus_message_iter_next(actions);
-
- printf("\t");
- print_sanitized(key, "\n\\");
- printf(": ");
- print_sanitized(value, "\n\\");
- printf("%s", delimiter);
- }
-
- printf("body: ");
- print_sanitized(body, "\n\\");
- printf("%ssummary: ", delimiter);
- print_sanitized(summary, "\n\\");
- printf("%s", delimiter);
-}
-
-static void json_output(const char *app_name, const char *app_icon, dbus_uint32_t id, dbus_uint32_t replaces_id,
- dbus_int32_t timeout, DBusMessageIter *hints, DBusMessageIter *actions, const char *summary,
- const char *body, const char *delimiter) {
+ DBusMessageIter i;
const char *sep = "";
+ const char *json_spec = "\\\n\r\b\f\"";
printf("{"
- "\"id\": %" PRIu32 ", "
- "\"app_name\": \"", id);
- print_sanitized(app_name, "\n\\\"");
- printf("\", "
- "\"app_icon\": \"");
- print_sanitized(app_icon, "\n\\\"");
- printf("\", "
- "\"replaces_id\": %" PRIu32 ", "
+ "\"id\": %" PRIu32 ", ", id);
+ if (d->app_name)
+ esc_printf(json_spec, "\"app_name\": \"%s\", ", d->app_name);
+ if (d->icon)
+ esc_printf(json_spec, "\"app_icon\": \"%s\", ", d->icon);
+ printf("\"replaces_id\": %" PRIu32 ", "
"\"timeout\": %" PRId32 ", ",
- replaces_id, timeout);
+ d->replaces, d->expiry_ms);
printf("\"hints\": {");
- hints_output_iterator(hints, "\"", "\": ", "\"", "\"", "\n\\\"", ", ", 1);
+ for (i = d->hints;
+ dbus_message_iter_get_arg_type(&i) != DBUS_TYPE_INVALID;
+ dbus_message_iter_next(&i)) {
+ DBusMessageIter di;
+ const char *key;
+
+ dbus_message_iter_recurse(&i, &di);
+ dbus_message_iter_get_basic(&di, &key);
+ dbus_message_iter_next(&di);
+ dbus_message_iter_recurse(&di, &di);
+
+ esc_printf(json_spec, "%s\"%z\": %D", sep, key, &di);
+ sep = ", ";
+ }
printf("}, \"actions\": {");
- while (dbus_message_iter_get_arg_type(actions) != DBUS_TYPE_INVALID) {
- if (!dbus_message_iter_has_next(actions))
- break;
+ sep = "";
+ for (i = d->actions;
+ dbus_message_iter_get_arg_type(&i) == DBUS_TYPE_STRING;
+ dbus_message_iter_next(&i)) {
const char *key;
const char *value;
- dbus_message_iter_get_basic(actions, &key);
- dbus_message_iter_next(actions);
- dbus_message_iter_get_basic(actions, &value);
- dbus_message_iter_next(actions);
+ if (!dbus_message_iter_has_next(&i))
+ break;
- printf("\"");
- print_sanitized(key, "\n\\\"");
- printf("\": \"");
- print_sanitized(value, "\n\\\"");
- printf("\"%s", sep);
+ dbus_message_iter_get_basic(&i, &key);
+ dbus_message_iter_next(&i);
+ dbus_message_iter_get_basic(&i, &value);
+
+ esc_printf(json_spec, "%s\"%z\": \"%z\"", sep, key, value);
sep = ", ";
}
- printf("}, ");
- printf("\"summary\": \"");
- print_sanitized(summary, "\n\\\"");
- printf("\", "
- "\"body\": \"");
- print_sanitized(body, "\n\\\"");
- printf("\"}%s", delimiter);
+ esc_printf(json_spec,
+ "}, "
+ "\"summary\": \"%z\", "
+ "\"body\": \"%z\""
+ "}", d->summary, d->body, delimiter);
}
-void output_notification(DBusMessage *message, dbus_uint32_t id, enum output_format fmt, const char *delimiter)
+void output_notification(uint32_t id, struct notification_data *notif)
{
- DBusMessageIter i;
- DBusMessageIter actions;
- DBusMessageIter hints;
- const char *app_name;
- dbus_uint32_t replaces_id;
- dbus_int32_t timeout;
- const char *app_icon;
- const char *summary;
- const char *body;
-
- dbus_message_iter_init(message, &i);
- dbus_message_iter_get_basic(&i, &app_name);
- dbus_message_iter_next(&i);
- dbus_message_iter_get_basic(&i, &replaces_id);
- dbus_message_iter_next(&i);
- dbus_message_iter_get_basic(&i, &app_icon);
- dbus_message_iter_next(&i);
- dbus_message_iter_get_basic(&i, &summary);
- dbus_message_iter_next(&i);
- dbus_message_iter_get_basic(&i, &body);
-
- dbus_message_iter_next(&i);
- dbus_message_iter_recurse(&i, &actions);
-
- dbus_message_iter_next(&i);
- dbus_message_iter_recurse(&i, &hints);
-
- dbus_message_iter_next(&i);
- dbus_message_iter_get_basic(&i, &timeout);
-
- switch (fmt) {
- case FORMAT_JSON:
- json_output(app_name, app_icon, id, replaces_id,
- timeout, &hints, &actions, summary, body,
- delimiter);
- break;
- case FORMAT_TEXT:
- default:
- default_output(app_name, app_icon, id, replaces_id,
- timeout, &hints, &actions, summary, body,
- delimiter);
- }
-
+ json_output(id, notif, ", ");
fflush(stdout);
}
diff --git a/output.h b/output.h
@@ -1,10 +1,14 @@
-#pragma once
+#ifndef OUTPUT_H
+#define OUTPUT_H
#include <dbus/dbus.h>
+#include "tmisu.h"
enum output_format {
FORMAT_TEXT,
FORMAT_JSON
};
-void output_notification(DBusMessage *message, dbus_uint32_t id, enum output_format fmt, const char *delimiter);
+void output_notification(dbus_uint32_t id, struct notification_data *notif);
+
+#endif
diff --git a/tmisu.c b/tmisu.c
@@ -5,7 +5,6 @@
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
-#include <getopt.h>
#include <time.h>
#include <sys/poll.h>
#include <sys/wait.h>
@@ -31,11 +30,10 @@ struct conf {
struct notification {
struct notification *next;
+ struct notification_data d;
DBusMessage *msg;
dbus_uint32_t id;
time_t expiry;
- const char *title;
- const char *body;
pid_t child;
};
@@ -207,47 +205,47 @@ time_t timeout_next_expiry(void)
static void notif_spawn(struct notification *n)
{
- if (cmd) {
- n->child = fork();
- switch (n->child) {
- case -1:
- groan("fork() failed:");
- n->child = 0;
- break;
- case 0:
- close(STDIN_FILENO);
- open("/dev/null", O_RDONLY);
- close(STDOUT_FILENO);
- open("/dev/null", O_WRONLY);
- execlp(cmd, cmd, n->title, n->body, NULL);
- exit(1);
- break;
- default:
- break;
- }
+ if (!cmd) {
+ n->child = 0;
+ return;
+ }
+
+ n->child = fork();
+ switch (n->child) {
+ case -1:
+ groan("fork() failed:");
+ n->child = 0;
+ break;
+ case 0:
+ close(STDIN_FILENO);
+ open("/dev/null", O_RDONLY);
+ close(STDOUT_FILENO);
+ open("/dev/null", O_WRONLY);
+ execlp(cmd, cmd, n->d.summary, n->d.body, NULL);
+ exit(1);
+ break;
+ default:
+ break;
}
}
const struct notification *notif_update(DBusMessage *msg,
- dbus_uint32_t id,
- const char *title,
- const char *body,
+ struct notification_data *d,
time_t expiry)
{
struct notification *i;
- for (i = notifications; i && i->id != id; i = i->next);
+ for (i = notifications; i && i->id != d->replaces; i = i->next);
if (!i)
return NULL;
- changed |= use_json || strcmp(title, i->title);
+ changed |= use_json || strcmp(d->summary, i->d.summary);
dbus_message_unref(i->msg);
if (cmd && i->child)
kill(i->child, SIGTERM);
- i->title = title;
- i->body = body;
+ memcpy(&i->d, d, sizeof(i->d));
i->expiry = expiry;
i->msg = dbus_message_ref(msg);
@@ -257,8 +255,7 @@ const struct notification *notif_update(DBusMessage *msg,
}
const struct notification *notif_add(DBusMessage *msg,
- const char *title,
- const char *body,
+ struct notification_data *d,
time_t expiry)
{
static dbus_uint32_t notification_id = 0;
@@ -268,8 +265,7 @@ const struct notification *notif_add(DBusMessage *msg,
if (!(nn->id = ++notification_id))
nn->id = ++notification_id;
nn->msg = dbus_message_ref(msg);
- nn->title = title;
- nn->body = body;
+ memcpy(&nn->d, d, sizeof(nn->d));
nn->expiry = expiry;
nn->next = NULL;
@@ -375,28 +371,39 @@ void notif_check_expiry(void)
}
}
-static const char *esc(const char *string, const char *escape) {
+static void writ(const char *part, size_t plen, void *data)
+{
+ fwrite(part, 1, plen, data);
+}
+
+static void esc(const char *string, const char *escape,
+ void (*cb)(const char *part, size_t plen, void *data),
+ void *data) {
static char buffer[1024];
static const char *special = "\b\f\n\r\t";
static const char *sp_rep = "bfnrt";
size_t p = 0;
while (*string) {
- size_t len = strcspn(string, escape);
- memcpy(buffer + p, string, len);
- string += len;
- p += len;
- while (*string && strchr(escape, *string)) {
- const char *sp;
- buffer[p++] = '\\';
- if ((sp = strchr(special, *string)))
- buffer[p++] = sp_rep[sp - special];
- else
- buffer[p++] = *string;
- string++;
+ while (*string && p < sizeof(buffer)) {
+ size_t len = strcspn(string, escape);
+ if (len > sizeof(buffer) - p)
+ len = sizeof(buffer) - p;
+ memcpy(buffer + p, string, len);
+ string += len;
+ p += len;
+ while (*string && strchr(escape, *string)) {
+ const char *sp;
+ buffer[p++] = '\\';
+ if ((sp = strchr(special, *string)))
+ buffer[p++] = sp_rep[sp - special];
+ else
+ buffer[p++] = *string;
+ string++;
+ }
}
+ cb(buffer, p, data);
+ p = 0;
}
- buffer[p] = '\0';
- return buffer;
}
void notif_dump(void)
@@ -409,9 +416,9 @@ void notif_dump(void)
for (i = notifications; i; i = i->next) {
printf("%s", sep);
if (use_json)
- output_notification(i->msg, i->id, FORMAT_JSON, "");
+ output_notification(i->id, &i->d);
else
- printf("%s", esc(i->title, "\\\r\n\t\b\f"));
+ esc(i->d.summary, "\\\r\n\t\b\f", writ, stdout);
sep = delimiter;
}
if (use_json)
@@ -506,14 +513,11 @@ DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *messag
if (d.replaces)
n = notif_update(message,
- d.replaces,
- d.summary,
- d.body,
+ &d,
expiry);
if (!n)
n = notif_add(message,
- d.summary,
- d.body,
+ &d,
expiry);
reply = dbus_message_new_method_return(message);