ap

An audio player suited to my tastes
Log | Files | Refs | README | LICENSE

commit dd0866460d180722136dfe41b83362825c002e8e
parent 998fd4e66fcc49b732b3fac151c0271d4dc17943
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Sun,  5 Sep 2021 17:46:48 -0700

Quote server responses

By quoting server responses 'ok' and 'error: *' can be sent to the
client. Additionally, although I'm unsure how useful it is, raw
responses can be sent back as is.

Diffstat:
MTODO | 2--
Maps/aps.c | 3++-
Maps/asplit.c | 6+++---
Maps/asplit.h | 2+-
Maps/response.c | 21+++++++++++++++++----
Maps/split.c | 33+++++++++++++++++++++++++--------
Maps/split.h | 2+-
Minclude/ap/ap.h | 3---
Minclude/ap/quote.h | 3++-
Mlib/ap/client.c | 10++++++++--
Mlib/ap/quote.c | 58+++++++++++++++++++++++++++++++++++++++++++++++++---------
11 files changed, 108 insertions(+), 35 deletions(-)

diff --git a/TODO b/TODO @@ -1,3 +1 @@ -- Allow 'ok' and 'error: *' items -- Consider quoting return items (which would fix 'ok' and 'error: *' items) - Use size_t for buffer sizes diff --git a/aps/aps.c b/aps/aps.c @@ -19,6 +19,7 @@ #include <sys/socket.h> +#include <ctype.h> #include <errno.h> #include <limits.h> #include <poll.h> @@ -207,7 +208,7 @@ aps_command(struct aps *aps, int s) buf = aps->clients[s].request; aps_logfmt(aps, COMMAND, s, "input '%s'", buf->data); - argv = asplit(buf->data, AP_QUOTE, AP_ARG_SEPS); + argv = asplit(buf->data, isspace); if (argv == NULL) return 1; if (*argv == NULL) { diff --git a/aps/asplit.c b/aps/asplit.c @@ -23,7 +23,7 @@ #include "split.h" char ** -asplit(char *s, char quote, char *sep) +asplit(char *s, int (*issep)(int)) { char **args, *copy; unsigned int len; @@ -31,12 +31,12 @@ asplit(char *s, char quote, char *sep) copy = strdup(s); if (copy == NULL) return NULL; - len = split(NULL, 0, copy, quote, sep); + len = split(NULL, 0, copy, issep); free(copy); args = calloc(++len, sizeof(*args)); if (args == NULL) return NULL; - split(args, len, s, quote, sep); + split(args, len, s, issep); return args; } diff --git a/aps/asplit.h b/aps/asplit.h @@ -1 +1 @@ -char **asplit(char *, char, char *); +char **asplit(char *, int (*)(int)); diff --git a/aps/response.c b/aps/response.c @@ -55,12 +55,25 @@ respfree(struct aps *aps, int fd) } int +allquote(int c) +{ + return 1; +} + +int respadd(struct aps *aps, int fd, char *item) { - if (bufappend(RESP->buf, item, strlen(item)) || - bufappend(RESP->buf, "\n", 1)) + int status; + + item = apquote(item, (strcmp(item, "ok") ? NULL : allquote)); + if (item == NULL) return 1; - return 0; + + status = (bufappend(RESP->buf, item, strlen(item)) || + bufappend(RESP->buf, "\n", 1)); + free(item); + + return status; } int @@ -68,7 +81,7 @@ respfinish(struct aps *aps, int fd, char *error) { if (error == NULL) { /* NOTE: Perhaps it should return an error? */ - if (respadd(aps, fd, "ok")) + if (bufappend(RESP->buf, "ok\n", 3)) respfinish(aps, fd, errstr); } else { aps_logfmt(aps, COMMAND, fd, "error '%s'", error); diff --git a/aps/split.c b/aps/split.c @@ -22,16 +22,33 @@ #include "util.h" char * -unquote(char **sp, char quote, char *delim) +spanwhile(char *s, int (*func)(int)) +{ + while (*s && func(*s)) + ++s; + return s; +} + +char * +spanwhilenot(char *s, int (*func)(int)) +{ + while (*s && !func(*s)) + ++s; + return s; +} + +/* Unquoting should probably done in only one place... */ +char * +unquote(char **sp, int (*issep)(int)) { char *start; - start = *sp + strspn(*sp, delim); + start = spanwhile(*sp, issep); if (*start == '\0') return NULL; - if (*start != quote) { - *sp = start + strcspn(start, delim); + if (*start != '\'') { + *sp = spanwhilenot(start, issep); if (**sp != '\0') { **sp = 0; ++*sp; @@ -44,8 +61,8 @@ unquote(char **sp, char quote, char *delim) return NULL; for (; **sp; ++*sp) { - if (**sp == quote) { - if ((*sp)[1] != quote) { + if (**sp == '\'') { + if ((*sp)[1] != '\'') { **sp = 0; ++*sp; return start; @@ -59,12 +76,12 @@ unquote(char **sp, char quote, char *delim) } unsigned int -split(char **ap, unsigned int len, char *s, char quote, char *sep) +split(char **ap, unsigned int len, char *s, int (*sep)(int)) { char *p; unsigned int i; - for (i = 0; (p = unquote(&s, quote, sep)); ++i) { + for (i = 0; (p = unquote(&s, sep)); ++i) { if (i < len) ap[i] = p; } diff --git a/aps/split.h b/aps/split.h @@ -1 +1 @@ -unsigned int split(char **, unsigned int, char *, char, char *); +unsigned int split(char **, unsigned int, char *, int (*)(int)); diff --git a/include/ap/ap.h b/include/ap/ap.h @@ -1,6 +1,3 @@ -#define AP_QUOTE '\'' -#define AP_ARG_SEPS " \t" - #include "buf.h" #include "con.h" #include "item.h" diff --git a/include/ap/quote.h b/include/ap/quote.h @@ -1 +1,2 @@ -char *apquote(char *); +char *apquote(char *, int (*)(int)); +char *apunquote(char *); diff --git a/lib/ap/client.c b/lib/ap/client.c @@ -77,7 +77,7 @@ apc_msg(struct apc *apc) itm = apc->args; do { - arg = apquote(itm->path); + arg = apquote(itm->path, NULL); if (arg == NULL || bufappend(buf, arg, strlen(arg)) || bufappend(buf, " ", 1)) { free(arg); @@ -143,7 +143,7 @@ char * apc_read(struct apc *apc) { unsigned int len; - char *buf, *end; + char *buf, *end, *tmp; while ((end = memchr(apc->buf->data, '\n', apc->buf->len)) == NULL && apc_recv(apc) == 0) @@ -169,5 +169,11 @@ apc_read(struct apc *apc) apc->status = buf; return NULL; } + + if (*buf == '\'') { + tmp = apunquote(buf); + free(buf); + buf = tmp; + } return buf; } diff --git a/lib/ap/quote.c b/lib/ap/quote.c @@ -17,20 +17,28 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <sys/socket.h> - +#include <ctype.h> +#include <errno.h> #include <stdlib.h> #include <string.h> -#include <ap/ap.h> +int +apneedquote(char *s, int (*needquote)(int)) +{ + if (*s == 0) + return 1; + while (!iscntrl(*s) && !isspace(*s) && *s != '\'' && (!needquote || !needquote(*s))) + ++s; + return *s; +} char * -apquote(char *s) +apquote(char *s, int (*needquote)(int)) { char *buf, *p; size_t i; - if (!strchr(s, AP_QUOTE) && s[strcspn(s, AP_ARG_SEPS)] == '\0') + if (!apneedquote(s, needquote)) return strdup(s); buf = malloc(strlen(s) * 2 + 3); @@ -38,14 +46,46 @@ apquote(char *s) return NULL; p = buf; - *p++ = AP_QUOTE; + *p++ = '\''; for (i = 0; s[i]; ++i) { - if (s[i] == AP_QUOTE) - *p++ = AP_QUOTE; + if (s[i] == '\'') + *p++ = '\''; *p++ = s[i]; } - *p++ = AP_QUOTE; + *p++ = '\''; *p++ = '\0'; return buf; } + +char * +apunquote(char *s) +{ + size_t i; + char *buf, *bufp; + + if (s[0] != '\'') + return strdup(s); + + bufp = buf = malloc(strlen(s)); + if (buf == NULL) + return NULL; + + for (i = 1; s[i]; ++i, ++bufp) { + if (s[i] == '\'') { + ++i; + if (s[i] == '\0') { + *bufp = '\0'; + return buf; + } + if (s[i] != '\'') + break; + } + *bufp = s[i]; + + } + + free(buf); + errno = EINVAL; + return NULL; +}