ap

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

commit 73b28b65270c6f0c269da7f0c2bfb5da9690b848
parent 1236de179f19fd67c990430e734d4ef43b484580
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Wed, 14 Jul 2021 02:30:35 -0700

Make client library functions

- The apc_recv function was ditched in favor of using other buffered
  io libraries such as stdio

- The function to locate the socket file was made public (in apfile)
  allowing apcon to be by-passed

- Make the apc_send argument concatenation code a function which
  could be used generally

- Remove empty TODO list

Diffstat:
DTODO | 1-
Mapc/apc.c | 172++++++++++++++++++++++++++++++++++---------------------------------------------
Minclude/ap/ap.h | 4+++-
Ainclude/ap/apfile.h | 1+
Ainclude/ap/client.h | 2++
Mlib/ap/apcon.c | 14+-------------
Alib/ap/apfile.c | 31+++++++++++++++++++++++++++++++
Alib/ap/client.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/ap/mkfile | 2+-
9 files changed, 209 insertions(+), 115 deletions(-)

diff --git a/TODO b/TODO @@ -1 +0,0 @@ -- Create a client library using functions from apc.c diff --git a/apc/apc.c b/apc/apc.c @@ -19,10 +19,13 @@ #include <sys/socket.h> #include <errno.h> -#include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> + +#ifdef __OpenBSD__ #include <unistd.h> +#endif #include <ap.h> #include <aputil.h> @@ -30,134 +33,105 @@ #include "config.h" int -apc_send(struct apcon *c, char **argv) +run(FILE *bfd, char **argv, int argc) { - char buf[AP_LINE_MAX]; - int i; - int len; - int tmp; - - len = 0; - for (i = 0; argv[i] != NULL; ++i) { - tmp = strlen(argv[i]); - if (len + tmp + 1 > sizeof(buf)) { - errno = ENOBUFS; - return 1; - } - memcpy(buf + len, argv[i], tmp); - len += tmp; - buf[len++] = *AP_ARG_SEPS; - } - buf[len - 1] = '\n'; - - return send(c->s, buf, len, 0) != len; -} + char *buf; + char *status; + size_t size; + ssize_t len; -int -dupstatus(char **bufp, char *responce) -{ - if (*bufp) - *bufp = NULL; - - if (strcmp(responce, "ok") == 0) - return 0; - if (strncmp(responce, "error: ", 7) == 0) { - if (bufp) - return (*bufp = strdup(responce + 7)) == NULL; - return 0; + if (argc == 0) { + errno = EINVAL; + return 1; } - errno = EBADMSG; - return 1; -} + if (apc_send(fileno(bfd), argv, argc)) + return 1; -int -apc_recv(struct apcon *c, char **err, int (*item)(char *)) -{ - char *end; - char buf[AP_LINE_MAX]; - int error; - int len; - int tmp; - - error = 0; - len = 0; - - while ((tmp = recv(c->s, buf + len, sizeof(buf) - len, 0)) > 0) { - len += tmp; - while ((end = memchr(buf, '\n', len))) { - *end = 0; - if (dupstatus(err, buf) == 0) - return error; - else if (errno != EBADMSG) + buf = NULL; + size = 0; + while ((len = getline(&buf, &size, bfd)) != -1) { + if (len && buf[len - 1] == '\n') + buf[--len] = 0; + if ((status = apc_status(buf))) { + if (strcmp(status, "ok") != 0) { + errno = 0; + fprintf(stderr, "aps: %s\n", status); + free(buf); + return 1; + } + free(buf); + return 0; + } else { + if (puts(buf) < 0) { + free(buf); return 1; - if (!error) - error = item(buf); - len -= end - buf + 1; - memmove(buf, end + 1, len); + } } } - if (tmp == 0) - errno = ECONNRESET; - return 1; -} - -int -apc_run(struct apcon *con, char **err, int (*item)(char *), char **argv) -{ - if (*err) - *err = NULL; - if (apc_send(con, argv) || apc_recv(con, err, item)) - return 1; - return 0; -} - -int -print(char *item) -{ - return puts(item) < 0; + free(buf); + return ferror(bfd); } int main(int argc, char **argv) { - char *p; + FILE *bfd; + char *buf; + char *path; int i; - char buf[AP_LINE_MAX]; - struct apcon con; + int sock; + int status; int sub; + size_t size; + ssize_t len; + + if (argc <= 1) + die("no command"); + + path = apfile(NULL); + if (path == NULL) + die("apfile"); + + sock = sopen(path, connect, SOCK_STREAM); + if (sock == -1) + die(path); + free(path); #ifdef __OpenBSD__ - if (pledge("stdio rpath unix", NULL)) + if (pledge("stdio", NULL)) die("pledge"); #endif - if (argc <= 1) - die("no command"); - - if (apcon_open(&con, NULL, connect, 0)) - die("unable to open connection"); + bfd = fdopen(sock, "w+"); + if (bfd == NULL) + die("fdopen"); sub = 0; for (i = 1; !sub && i < argc; ++i) if (strcmp(argv[i], substr) == 0) sub = i; + if (!sub) { - if (apc_run(&con, &p, print, argv + 1) || p) - die(p); + status = run(bfd, argv + 1, argc - 1); } else { - while (fgets(buf, sizeof(buf), stdin) != NULL) { - if ((p = strchr(buf, '\n')) == NULL) - die("message too long"); - *p = 0; - + buf = NULL; + size = 0; + status = 0; + while (status == 0 && + (len = getline(&buf, &size, stdin)) != -1) { + if (len && buf[len - 1] == '\n') + buf[--len] = 0; argv[sub] = buf; - if (apc_run(&con, &p, print, argv + 1) || p) - die(p); + status = run(bfd, argv + 1, argc - 1); } + free(buf); } - apcon_close(&con); - return 0; + if (shutdown(fileno(bfd), SHUT_RDWR) || fclose(bfd)) + die("unable to close connection"); + if (status && errno) + die(NULL); + return status; } diff --git a/include/ap/ap.h b/include/ap/ap.h @@ -2,5 +2,7 @@ #define AP_ARGV_MAX 128 #define AP_ARG_SEPS "\t" -#include "sock.h" #include "apcon.h" +#include "apfile.h" +#include "client.h" +#include "sock.h" diff --git a/include/ap/apfile.h b/include/ap/apfile.h @@ -0,0 +1 @@ +char *apfile(char *); diff --git a/include/ap/client.h b/include/ap/client.h @@ -0,0 +1,2 @@ +int apc_send(int, char **, unsigned int); +char * apc_status(char *); diff --git a/lib/ap/apcon.c b/lib/ap/apcon.c @@ -19,27 +19,15 @@ #include <sys/socket.h> #include <stdlib.h> -#include <string.h> #include <unistd.h> #include <ap.h> -char * -apcon_getpath(char *path) -{ - if (path == NULL) { - path = getenv("APSOCK"); - if (path == NULL) - path = "/tmp/aps"; - } - return strdup(path); -} - int apcon_open(struct apcon *apc, char *path, int (*init)(int, const struct sockaddr *, socklen_t), int flags) { - apc->path = apcon_getpath(path); + apc->path = apfile(path); if (apc->path == NULL) return 1; diff --git a/lib/ap/apfile.c b/lib/ap/apfile.c @@ -0,0 +1,31 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> + +char * +apfile(char *path) +{ + if (path == NULL) { + path = getenv("apsock"); + if (path == NULL) + path = "/tmp/aps"; + } + return strdup(path); +} diff --git a/lib/ap/client.c b/lib/ap/client.c @@ -0,0 +1,97 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> + +#include <ap.h> + +size_t +apc_memcat(char *dst, size_t dstsize, size_t dstlen, char *src, size_t srclen) +{ + if (dstlen > SIZE_MAX - srclen) { + errno = EOVERFLOW; + return 0; + } + if (dstlen + srclen > dstsize) { + errno = ENOBUFS; + return 0; + } + memcpy(dst + dstlen, src, srclen); + return dstlen + srclen; +} + +size_t +apc_strjoin(char *buf, size_t size, char *fs, char **strings, unsigned int nstrings) +{ + size_t len; + unsigned int i; + size_t fslen; + + len = 0; + fslen = strlen(fs); + for (i = 0; i < nstrings; ++i) { + if (i > 0) { + len = apc_memcat(buf, size, len, fs, fslen); + if (len == 0) + return 0; + } + len = apc_memcat(buf, size, len, strings[i], strlen(strings[i])); + if (len == 0) + return 0; + } + + return apc_memcat(buf, size, len, "", 1); +} + +int +apc_send(int s, char **argv, unsigned int argc) +{ + char buf[AP_LINE_MAX]; + char sep[2]; + size_t len; + + strlcpy(sep, AP_ARG_SEPS, sizeof(sep)); + len = apc_strjoin(buf, sizeof(buf), sep, argv, argc); + if (len == 0) + return 1; + + buf[len - 1] = '\n'; + return send(s, buf, len, 0) != len; +} + +char * +apc_status(char *s) +{ + char *ep; + int eplen; + + if (strcmp(s, "ok") == 0) + return s; + + ep = "error: "; + eplen = strlen(ep); + if (strncmp(s, ep, eplen) == 0) + return s + eplen; + + return NULL; +} diff --git a/lib/ap/mkfile b/lib/ap/mkfile @@ -1,7 +1,7 @@ # Copyright 2021 Jacob R. Edwards name = libap.a -src = apcon.c sock.c +src = apcon.c apfile.c client.c sock.c obj = ${src:%.c=%.o} hdir = ../../include/ap mk = ../../mk