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:
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