From 16436ef65b3bde49ff74d1bfa9144495059aafd5 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 12:28:32 -0400 Subject: Handle newlines in params --- mktrayicon.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 23 deletions(-) diff --git a/mktrayicon.c b/mktrayicon.c index 4ac4779..b6c456c 100644 --- a/mktrayicon.c +++ b/mktrayicon.c @@ -11,6 +11,9 @@ #include #include #include +#include + +#define DEBUG 1 GtkStatusIcon *icon; char *onclick = NULL; @@ -81,19 +84,21 @@ gboolean do_quit(gpointer data) gpointer watch_fifo(gpointer argv) { char *buf = malloc(1024*sizeof(char)); + char cmd; char *param; + char *tmp = malloc(1024*sizeof(char)); char *read; - size_t len; + size_t len, i; char *fifo_path = (char*)argv; FILE *fifo; struct stat fifo_st; /* outer is for open */ - while (1) { + outer: while (1) { if (stat(fifo_path, &fifo_st) != 0) { perror("FIFO does not exist, exiting\n"); gdk_threads_add_idle(do_quit, fifo); - break; + return NULL; } fifo = fopen(fifo_path, "r"); @@ -101,17 +106,20 @@ gpointer watch_fifo(gpointer argv) if (fifo == NULL) { perror("FIFO went away, exiting\n"); gdk_threads_add_idle(do_quit, fifo); - break; + return NULL; } /* inner is for read */ while (1) { + fprintf(stderr, "reading\n"); read = fgets(buf, 1024 * sizeof(char), fifo); + fprintf(stderr, "read\n"); if (read == NULL) { /* no more data in pipe, reopen and block */ fclose(fifo); - break; + fprintf(stderr, "closed\n"); + goto outer; } /* trim string */ @@ -121,28 +129,100 @@ gpointer watch_fifo(gpointer argv) if (*read == '\0') { /* empty command */ + fprintf(stderr, "empty\n"); continue; } - /* get rid of trailing newline */ - len = strlen(buf); - buf[len-1] = '\0'; - len -= 1; - - /* we have to malloc this on every call, because the memory is - * reused and the _idle functions are called asynchronously */ + cmd = *read; + fprintf(stderr, "cmd %c\n", cmd); + len = strlen(read); if (len < 3) { - param = malloc(1*sizeof(char)); - *param = '\0'; + param = NULL; + } else if (*(read + 2) != '\'') { + // unquoted string + read += 2; + len -= 2; + // trim trailing whitespace + i = len - 1; + while (i > 0) { + if (!isspace(read[i])) { + len = i + 1; + read[len] = '\0'; + break; + } + i -= 1; + } + param = malloc((len+1)*sizeof(char)); + strncpy(param, read, len+1); } else { - param = malloc((len-2+1)*sizeof(char)); - strncpy(param, buf+2, len-2+1); + // quoted string + read += 3; + len -= 3; + *tmp = '\0'; + *(tmp+1024-1) = '\0'; + // keep track of what we have so far + strncpy(tmp, read, 1023); + + // now keep reading until we have the end quote + while (1) { + // check for terminating ' + if (len != 0) { + // search backwards past whitespace + i = len - 1; + while (i > 0) { + if (!isspace(tmp[i])) { + break; + } + i -= 1; + } + if (tmp[i] == '\'') { + // maybe the end! + // let's make sure it isn't escaped + if (i >= 2 && tmp[i-2] == '\\') { + } else { + // it's not! + // we're done. + // trim off the ' and + // any whitespace we walked past + len = i; + tmp[len] = '\0'; + break; + } + } + } + + if (len == 1023) { + // we can't read any more + // but also haven't found the end + // forcibly terminate the string + fprintf(stderr, "Quoted string too long (max 1023 chars)\n"); + break; + } + + // we don't have the end of the string yet + read = fgets(buf, 1024 * sizeof(char), fifo); + if (read == NULL) { + /* no more data in pipe, reopen and block */ + fclose(fifo); + goto outer; + } + // note that we don't trim here, because we're + // in a quoted string. + strncpy(tmp + len, read, 1023 - len); + len += strlen(tmp + len); + } + + // quoted string is now in param[0:len] + param = malloc((len+1)*sizeof(char)); + strncpy(param, tmp, len+1); } - switch (*buf) { + switch (cmd) { case 'q': gdk_threads_add_idle(do_quit, param); - free(param); + if (param != NULL) { + free(param); + } break; case 't': /* tooltip */ gdk_threads_add_idle(set_tooltip, param); @@ -152,11 +232,15 @@ gpointer watch_fifo(gpointer argv) break; case 'h': /* hide */ gdk_threads_add_idle(set_visible, (void *)0); - free(param); + if (param != NULL) { + free(param); + } break; case 's': /* show */ gdk_threads_add_idle(set_visible, (void *)1); - free(param); + if (param != NULL) { + free(param); + } break; case 'c': /* click */ if (onclick != NULL) { @@ -164,7 +248,7 @@ gpointer watch_fifo(gpointer argv) onclick = NULL; } - if (*param == '\0') { + if (param != NULL && *param == '\0') { #ifdef DEBUG printf("Removing onclick handler\n"); #endif @@ -178,11 +262,15 @@ gpointer watch_fifo(gpointer argv) break; case 'm': /* menu */ fprintf(stderr, "Menu command not yet implemented\n"); - free(param); + if (param != NULL) { + free(param); + } break; default: fprintf(stderr, "Unknown command: '%c'\n", *buf); - free(param); + if (param != NULL) { + free(param); + } } gdk_flush(); -- cgit From e8122c14080dee0640091b52e171abeed4dd03ff Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 13:47:18 -0400 Subject: Remove debug prints --- mktrayicon.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mktrayicon.c b/mktrayicon.c index b6c456c..f815bb7 100644 --- a/mktrayicon.c +++ b/mktrayicon.c @@ -111,14 +111,11 @@ gpointer watch_fifo(gpointer argv) /* inner is for read */ while (1) { - fprintf(stderr, "reading\n"); read = fgets(buf, 1024 * sizeof(char), fifo); - fprintf(stderr, "read\n"); if (read == NULL) { /* no more data in pipe, reopen and block */ fclose(fifo); - fprintf(stderr, "closed\n"); goto outer; } @@ -129,12 +126,10 @@ gpointer watch_fifo(gpointer argv) if (*read == '\0') { /* empty command */ - fprintf(stderr, "empty\n"); continue; } cmd = *read; - fprintf(stderr, "cmd %c\n", cmd); len = strlen(read); if (len < 3) { param = NULL; -- cgit From 331b4aef50dc71b4e796993b0f2f91c37d6d5af3 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 15:41:16 -0400 Subject: Support both types of quotes --- mktrayicon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mktrayicon.c b/mktrayicon.c index f815bb7..becf60d 100644 --- a/mktrayicon.c +++ b/mktrayicon.c @@ -85,6 +85,7 @@ gpointer watch_fifo(gpointer argv) { char *buf = malloc(1024*sizeof(char)); char cmd; + char quote; char *param; char *tmp = malloc(1024*sizeof(char)); char *read; @@ -133,7 +134,7 @@ gpointer watch_fifo(gpointer argv) len = strlen(read); if (len < 3) { param = NULL; - } else if (*(read + 2) != '\'') { + } else if (*(read + 2) != '\'' && *(read + 2) != '"') { // unquoted string read += 2; len -= 2; @@ -151,6 +152,7 @@ gpointer watch_fifo(gpointer argv) strncpy(param, read, len+1); } else { // quoted string + quote = *(read+2); read += 3; len -= 3; *tmp = '\0'; @@ -170,7 +172,7 @@ gpointer watch_fifo(gpointer argv) } i -= 1; } - if (tmp[i] == '\'') { + if (tmp[i] == quote) { // maybe the end! // let's make sure it isn't escaped if (i >= 2 && tmp[i-2] == '\\') { -- cgit From 3d9a56d16417cb8d2f2e41fd1e75cfad81ab5a09 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 15:44:53 -0400 Subject: Mention quoted strings in README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c84a99c..f5e97d6 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,12 @@ Note that any script communicating with `mktrayicon` via the pipe **must**, for the time being, send `q` when they are done. Just removing the FIFO file will **not** cause the tray icon to be removed. +The command argument can be quoted with either `'` or `"` if you wish +it to include newlines. Other string interpolation may be added later. +Quoted strings are terminated by a matching quote at the end of a line +(ignoring whitespace). To escape a quote character at the end of a line +to continue a quoted string, prefix it with a `\`. + ## Why? Because I wanted to be able to create tray icons from bash without all the -- cgit From 43d22022e93e0d849518d1e3c38d4347b65034bd Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 18:32:24 -0400 Subject: No more debug by default --- mktrayicon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mktrayicon.c b/mktrayicon.c index becf60d..65506af 100644 --- a/mktrayicon.c +++ b/mktrayicon.c @@ -13,8 +13,6 @@ #include #include -#define DEBUG 1 - GtkStatusIcon *icon; char *onclick = NULL; -- cgit From e034fdb94dd68bebf950f6ea1c34d006633784e2 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 24 Oct 2019 18:33:28 -0400 Subject: Remove now-unused fifo var from main() --- mktrayicon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mktrayicon.c b/mktrayicon.c index 65506af..6f063a0 100644 --- a/mktrayicon.c +++ b/mktrayicon.c @@ -296,7 +296,6 @@ int main(int argc, char **argv) char *start_icon = "none"; char *tooltip = NULL; char *pipe = NULL; - FILE *fifo; GThread *reader; XInitThreads(); /* see http://stackoverflow.com/a/18690540/472927 */ -- cgit