commit b149d26ec695922c2a2f0606e15df7377ce6642d
parent 08349a15e62f64514098e77be9109de3edb4ef87
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date: Tue, 29 Jun 2021 19:26:10 -0700
Organize into subdirectories
Diffstat:
37 files changed, 1017 insertions(+), 979 deletions(-)
diff --git a/ap.h b/ap.h
@@ -1,4 +0,0 @@
-#define AP_LINE_MAX (PATH_MAX * 2)
-#define AP_ARGV_MAX 128
-
-static char *argseps = "\t";
diff --git a/apc.c b/apc.c
@@ -1,169 +0,0 @@
-/* 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "ap.h"
-#include "apcon.h"
-
-void
-die(char *s)
-{
- perror(s);
- exit(1);
-}
-
-int
-apc_send(struct apcon *c, char **argv)
-{
- 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++] = *argseps;
- }
- buf[len - 1] = '\n';
-
- return send(c->s, buf, len, 0) != 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;
- }
-
- errno = EBADMSG;
- 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)
- 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;
-}
-
-int
-main(int argc, char **argv)
-{
- char *p;
- int i;
- char buf[AP_LINE_MAX];
- struct apcon con;
- int sub;
-
-#ifdef __OpenBSD__
- if (pledge("stdio rpath unix", NULL))
- die("pledge");
-#endif
-
- if (argc <= 1)
- die("no command");
-
- if (apcon_open(&con, NULL, connect, 0))
- die("unable to open connection");
-
- sub = 0;
- for (i = 1; !sub && i < argc; ++i)
- if (strcmp(argv[i], "-") == 0)
- sub = i;
- if (!sub) {
- if (apc_run(&con, &p, print, argv + 1) || p)
- die(p);
- } else {
- while (fgets(buf, sizeof(buf), stdin) != NULL) {
- if ((p = strchr(buf, '\n')) == NULL)
- die("message too long");
- *p = 0;
-
- argv[sub] = buf;
- if (apc_run(&con, &p, print, argv + 1) || p)
- die(p);
- }
- }
-
- apcon_close(&con);
- return 0;
-}
diff --git a/apc/apc b/apc/apc
Binary files differ.
diff --git a/apc/apc.c b/apc/apc.c
@@ -0,0 +1,168 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <ap.h>
+
+void
+die(char *s)
+{
+ perror(s);
+ exit(1);
+}
+
+int
+apc_send(struct apcon *c, char **argv)
+{
+ 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;
+}
+
+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;
+ }
+
+ errno = EBADMSG;
+ 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)
+ 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;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *p;
+ int i;
+ char buf[AP_LINE_MAX];
+ struct apcon con;
+ int sub;
+
+#ifdef __OpenBSD__
+ if (pledge("stdio rpath unix", NULL))
+ die("pledge");
+#endif
+
+ if (argc <= 1)
+ die("no command");
+
+ if (apcon_open(&con, NULL, connect, 0))
+ die("unable to open connection");
+
+ sub = 0;
+ for (i = 1; !sub && i < argc; ++i)
+ if (strcmp(argv[i], "-") == 0)
+ sub = i;
+ if (!sub) {
+ if (apc_run(&con, &p, print, argv + 1) || p)
+ die(p);
+ } else {
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ if ((p = strchr(buf, '\n')) == NULL)
+ die("message too long");
+ *p = 0;
+
+ argv[sub] = buf;
+ if (apc_run(&con, &p, print, argv + 1) || p)
+ die(p);
+ }
+ }
+
+ apcon_close(&con);
+ return 0;
+}
diff --git a/apc/mkfile b/apc/mkfile
@@ -0,0 +1,16 @@
+# Copyright 2021 Jacob R. Edwards
+
+name = apc
+src = apc.c
+obj = ${src:%.c=%.o}
+
+cppflags = -I../lib
+ldflags = -L../lib
+ldlibs = -lap
+
+all:V: $name
+
+< ../mk/config.mk
+< ../mk/clean.mk
+< ../mk/obj.mk
+< ../mk/prog.mk
diff --git a/apcon.c b/apcon.c
@@ -1,65 +0,0 @@
-/* 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 <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "apcon.h"
-#include "config.h"
-#include "sock.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);
- if (apc->path == NULL)
- return 1;
-
- apc->s = sopen(apc->path, init, SOCK_STREAM | flags);
- if (apc->s == -1) {
- free(apc->path);
- return 1;
- }
-
- apc->init = init;
- return 0;
-}
-
-void
-apcon_close(struct apcon *apc)
-{
- sclose(apc->s);
- if (apc->init == bind)
- unlink(apc->path);
- free(apc->path);
-}
diff --git a/aps.c b/aps.c
@@ -1,218 +0,0 @@
-/* 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 <sys/un.h>
-
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <limits.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "ap.h"
-#include "apcon.h"
-#include "command.h"
-#include "config.h"
-#include "player.h"
-#include "queue.h"
-#include "response.h"
-#include "sock.h"
-#include "util.h"
-
-#include "aps.h"
-
-static struct aps aps;
-
-void
-die(char *s)
-{
- perror(s);
- exit(1);
-}
-
-void
-sigclose(int sig)
-{
- aps.close = 1;
-}
-
-void
-sigchld(int sig)
-{
- int status;
- pid_t pid;
-
- while ((pid =
- waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) {
- if (pid == aps.player.pid)
- pupdate(&aps.player, status);
- }
-}
-
-int
-aps_accept(struct aps *aps)
-{
- int s;
- struct pollfd pfd;
- int r;
-
- pfd.events = POLLIN;
- pfd.fd = aps->con.s;
-
- r = poll(&pfd, 1, aps->nfds ? 0 : INFTIM);
- if (r <= 0)
- return r;
-
- while ((s = accept4(aps->con.s, NULL, NULL, 0)) >= 0) {
- aps->pfds[s].fd = s;
- ++aps->nfds;
- }
-
- return errno != EWOULDBLOCK;
-}
-
-int
-aps_drop(struct aps *aps, int fd)
-{
- aps->pfds[fd].fd = -1;
- resp_free(aps, fd);
- --aps->nfds;
- return sclose(fd);
-}
-
-int
-aps_handle(struct aps *aps, int fd)
-{
- if (aps->pfds[fd].revents & (POLLERR | POLLHUP | POLLNVAL)) {
- return 1;
- } else if (aps->pfds[fd].revents & POLLIN) {
- if (aps_command(aps, fd))
- return 1;
- } else if (aps->pfds[fd].revents & POLLOUT) {
- if (aps->clients[fd].response.lock && resp_send(aps, fd))
- return 1;
- } else {
- die("unhandled poll revent");
- }
-
- return 0;
-}
-
-int
-aps_update(struct aps *aps)
-{
- int i;
- int re;
-
- if ((re = poll(aps->pfds, LEN(aps->pfds), timeout)) == -1)
- return 1;
-
- for (i = 0; re > 0 && i < LEN(aps->pfds); ++i) {
- if (aps->pfds[i].revents && aps_handle(aps, i)) {
- aps_drop(aps, i);
- --re;
- }
- }
-
- return 0;
-}
-
-int
-run(struct aps *aps)
-{
- while (!aps->close) {
- if (!aps->player.state && aps->queue.pos)
- aps_next(aps, -1, 0, NULL);
- if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR)
- return 1;
- }
- return 0;
-}
-
-int
-aps_open(struct aps *aps)
-{
- int i;
-
- if (apcon_open(&aps->con, NULL, bind, SOCK_NONBLOCK) ||
- listen(aps->con.s, 10))
- return 1;
-
- for (i = 0; i < LEN(aps->pfds); ++i) {
- aps->pfds[i].fd = -1;
- aps->pfds[i].events = POLLIN | POLLOUT;
- }
- return 0;
-}
-
-void
-aps_close(struct aps *aps)
-{
- int i;
-
- for (i = 0; i < LEN(aps->next); ++i)
- free(aps->next[i]);
- for (i = 0; i < LEN(aps->pfds); ++i)
- if (aps->pfds[i].fd != -1)
- aps_drop(aps, i);
- apcon_close(&aps->con);
- pstop(&aps->player);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
-
-#ifdef __OpenBSD__
- if (pledge("stdio rpath cpath proc exec unix", NULL))
- die("pledge");
-#endif
-
- signal(SIGCHLD, sigchld);
- signal(SIGINT, sigclose);
- signal(SIGTERM, sigclose);
-
- for (i = 1; player[i]; ++i)
- if (!player[i][0])
- player[i] = aps.player.path;
-
- if (aps_next(&aps, -1, LEN(next), next))
- die("aps_next");
-
- aps.player.argv = player + 1;
- aps.player.prog = player[0];
- aps.player.state = STOPPED;
-
- if (aps_open(&aps))
- die("open connection");
- if (run(&aps)) {
- perror("error");
- aps_close(&aps);
- return 1;
- }
-
- aps_close(&aps);
- return 0;
-}
diff --git a/aps/aps b/aps/aps
Binary files differ.
diff --git a/aps/aps.c b/aps/aps.c
@@ -0,0 +1,217 @@
+/* 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 <sys/un.h>
+
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <ap.h>
+
+#include "command.h"
+#include "config.h"
+#include "player.h"
+#include "queue.h"
+#include "response.h"
+#include "util.h"
+
+#include "aps.h"
+
+static struct aps aps;
+
+void
+die(char *s)
+{
+ perror(s);
+ exit(1);
+}
+
+void
+sigclose(int sig)
+{
+ aps.close = 1;
+}
+
+void
+sigchld(int sig)
+{
+ int status;
+ pid_t pid;
+
+ while ((pid =
+ waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) {
+ if (pid == aps.player.pid)
+ pupdate(&aps.player, status);
+ }
+}
+
+int
+aps_accept(struct aps *aps)
+{
+ int s;
+ struct pollfd pfd;
+ int r;
+
+ pfd.events = POLLIN;
+ pfd.fd = aps->con.s;
+
+ r = poll(&pfd, 1, aps->nfds ? 0 : INFTIM);
+ if (r <= 0)
+ return r;
+
+ while ((s = accept4(aps->con.s, NULL, NULL, 0)) >= 0) {
+ aps->pfds[s].fd = s;
+ ++aps->nfds;
+ }
+
+ return errno != EWOULDBLOCK;
+}
+
+int
+aps_drop(struct aps *aps, int fd)
+{
+ aps->pfds[fd].fd = -1;
+ resp_free(aps, fd);
+ --aps->nfds;
+ return sclose(fd);
+}
+
+int
+aps_handle(struct aps *aps, int fd)
+{
+ if (aps->pfds[fd].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ return 1;
+ } else if (aps->pfds[fd].revents & POLLIN) {
+ if (aps_command(aps, fd))
+ return 1;
+ } else if (aps->pfds[fd].revents & POLLOUT) {
+ if (aps->clients[fd].response.lock && resp_send(aps, fd))
+ return 1;
+ } else {
+ die("unhandled poll revent");
+ }
+
+ return 0;
+}
+
+int
+aps_update(struct aps *aps)
+{
+ int i;
+ int re;
+
+ if ((re = poll(aps->pfds, LEN(aps->pfds), timeout)) == -1)
+ return 1;
+
+ for (i = 0; re > 0 && i < LEN(aps->pfds); ++i) {
+ if (aps->pfds[i].revents && aps_handle(aps, i)) {
+ aps_drop(aps, i);
+ --re;
+ }
+ }
+
+ return 0;
+}
+
+int
+run(struct aps *aps)
+{
+ while (!aps->close) {
+ if (!aps->player.state && aps->queue.pos)
+ aps_next(aps, -1, 0, NULL);
+ if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR)
+ return 1;
+ }
+ return 0;
+}
+
+int
+aps_open(struct aps *aps)
+{
+ int i;
+
+ if (apcon_open(&aps->con, NULL, bind, SOCK_NONBLOCK) ||
+ listen(aps->con.s, 10))
+ return 1;
+
+ for (i = 0; i < LEN(aps->pfds); ++i) {
+ aps->pfds[i].fd = -1;
+ aps->pfds[i].events = POLLIN | POLLOUT;
+ }
+ return 0;
+}
+
+void
+aps_close(struct aps *aps)
+{
+ int i;
+
+ for (i = 0; i < LEN(aps->next); ++i)
+ free(aps->next[i]);
+ for (i = 0; i < LEN(aps->pfds); ++i)
+ if (aps->pfds[i].fd != -1)
+ aps_drop(aps, i);
+ apcon_close(&aps->con);
+ pstop(&aps->player);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+
+#ifdef __OpenBSD__
+ if (pledge("stdio rpath cpath proc exec unix", NULL))
+ die("pledge");
+#endif
+
+ signal(SIGCHLD, sigchld);
+ signal(SIGINT, sigclose);
+ signal(SIGTERM, sigclose);
+
+ for (i = 1; player[i]; ++i)
+ if (!player[i][0])
+ player[i] = aps.player.path;
+
+ if (aps_next(&aps, -1, LEN(next), next))
+ die("aps_next");
+
+ aps.player.argv = player + 1;
+ aps.player.prog = player[0];
+ aps.player.state = STOPPED;
+
+ if (aps_open(&aps))
+ die("open connection");
+ if (run(&aps)) {
+ perror("error");
+ aps_close(&aps);
+ return 1;
+ }
+
+ aps_close(&aps);
+ return 0;
+}
diff --git a/aps.h b/aps/aps.h
diff --git a/aps/command.c b/aps/command.c
@@ -0,0 +1,360 @@
+/* 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 <ctype.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <ap.h>
+
+#include "player.h"
+#include "queue.h"
+#include "response.h"
+#include "util.h"
+
+#include "aps.h"
+
+static char *earg = "Invalid number of arguments";
+static char *enotfound = "Not found";
+static char *eposition = "No position in queue";
+static char *etoofew = "Too few arguments";
+
+int
+resp_finish(struct aps *aps, int s, char *error)
+{
+ char buf[AP_LINE_MAX];
+ int len;
+
+ if (error) {
+ len = snprintf(buf, sizeof(buf), "error: %s\n", error);
+ } else {
+ len = 3;
+ memcpy(buf, "ok\n", len);
+ }
+
+ if (len >= sizeof(buf))
+ ERET(EMSGSIZE);
+ if (resp_add(aps, s, buf, len))
+ return 1;
+ resp_end(aps, s);
+ return 0;
+}
+
+int
+resp_additem(struct aps *aps, int s, char *item)
+{
+ char buf[AP_LINE_MAX];
+ int n;
+
+ n = snprintf(buf, sizeof(buf), "%s\n", item);
+ if (n >= sizeof(buf))
+ ERET(EMSGSIZE);
+ return resp_add(aps, s, buf, n);
+}
+
+int
+match(char *pattern, struct item *item)
+{
+ return fnmatch(pattern, item->path, 0) == 0;
+}
+
+struct item *
+nextmatch(struct item *(*incr)(struct item *), struct item *item,
+ char **patterns, int len, int noneall)
+{
+ int i;
+
+ if (len == 0 || !item)
+ return (noneall ? item : NULL);
+ for (; item; item = incr(item)) {
+ for (i = 0; i < len; ++i) {
+ if (match(patterns[i], item))
+ return item;
+ }
+ }
+ return item;
+}
+
+char *
+aps_add(struct aps *aps, int s, int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; ++i) {
+ if (queue_add(&aps->queue, argv[i]))
+ return strerror(errno);
+ }
+ return NULL;
+}
+
+char *
+aps_remove(struct aps *aps, int s, int argc, char **argv)
+{
+ struct item *item, *next;
+
+ if (argc == 1) {
+ if (aps->queue.pos == NULL)
+ return eposition;
+ queue_remove(&aps->queue, aps->queue.pos);
+ }
+
+ next = aps->queue.head;
+ while ((item = nextmatch(item_next, next, argv + 1, argc - 1, 0))) {
+ next = item->next;
+ queue_remove(&aps->queue, item);
+ }
+
+ return NULL;
+}
+
+char *
+aps_list(struct aps *aps, int s, int argc, char **argv)
+{
+ struct item *item;
+
+ item = aps->queue.head;
+ while ((item = nextmatch(item_next, item, argv + 1, argc - 1, 1))) {
+ if (resp_additem(aps, s, item->path))
+ return strerror(errno);
+ item = item->next;
+ }
+
+ return NULL;
+}
+
+struct item *
+findnum(struct item *(*incr)(struct item *), struct item *item, char *num,
+ char **err)
+{
+ int n;
+
+ n = strtonum(num, 0, INT_MAX, err);
+ if (*err)
+ return NULL;
+ *err = enotfound;
+ return item_seek(incr, item, n);
+}
+
+struct item *
+findpat(struct item *(*incr)(struct item *), struct item *item,
+ char **patterns, int len, char **err)
+{
+ *err = enotfound;
+ return nextmatch(incr, item, patterns, len, 0);
+}
+
+struct item *
+find(struct aps *aps, int argc, char **argv, char **err)
+{
+ char *e;
+ struct item *(*incr)(struct item *);
+ struct item *item;
+
+ ++argv;
+ --argc;
+ if (argc < 1) {
+earg:
+ *err = earg;
+ return NULL;
+ }
+
+ incr = item_next;
+ item = aps->queue.pos;
+ if (argc > 1 && strchr("+-^", **argv) && !argv[0][1]) {
+ switch (**argv) {
+ case '-':
+ incr = item_prev;
+ break;
+ case '^':
+ item = aps->queue.head;
+ break;
+ }
+ ++argv;
+ --argc;
+ }
+
+ if (!isdigit(**argv)) {
+ return findpat(incr, incr(item), argv, argc, err);
+ } else {
+ if (argc != 1)
+ goto earg;
+ return findnum(incr, item, *argv, err);
+ }
+}
+
+char *
+aps_seek(struct aps *aps, int s, int argc, char **argv)
+{
+ char *err;
+ struct item *item;
+
+ item = find(aps, argc, argv, &err);
+ if (item == NULL)
+ return err;
+ aps->queue.pos = item;
+ return NULL;
+}
+
+char *
+aps_play(struct aps *aps, int s, int argc, char **argv)
+{
+ char *err;
+
+ if (argc <= 1) {
+ if (aps->queue.pos == NULL)
+ return eposition;
+ } else if ((err = aps_seek(aps, s, argc, argv))) {
+ return err;
+ }
+
+ if (pplay(&aps->player, aps->queue.pos->path))
+ return strerror(errno);
+ return NULL;
+}
+
+char *
+aps_pause(struct aps *aps, int s, int argc, char **argv)
+{
+ if (psuspend(&aps->player))
+ return strerror(errno);
+ return NULL;
+}
+
+char *
+aps_stop(struct aps *aps, int s, int argc, char **argv)
+{
+ if (pstop(&aps->player))
+ return strerror(errno);
+ return NULL;
+}
+
+char *
+aps_toggle(struct aps *aps, int s, int argc, char **argv)
+{
+ if (ptoggle(&aps->player))
+ return strerror(errno);
+ return NULL;
+}
+
+char *
+aps_name(struct aps *aps, int s, int argc, char **argv)
+{
+ struct item *item;
+ char *err;
+
+ if (argc < 2)
+ item = aps->queue.pos;
+ else
+ item = find(aps, argc, argv, &err);
+ if (item == NULL)
+ return err;
+
+ if (resp_additem(aps, s, item->path))
+ return strerror(errno);
+ return NULL;
+}
+
+char *
+aps_next(struct aps *aps, int s, int argc, char **argv)
+{
+ int i;
+
+ if (argc > 1) {
+ for (i = 0; i < argc; ++i) {
+ free(aps->next[i]);
+ aps->next[i] = strdup(argv[i]);
+ if (aps->next[i] == NULL)
+ return strerror(errno);
+ }
+ aps->nextlen = i;
+ return NULL;
+ }
+
+ pstop(&aps->player);
+ return aps_play(aps, -1, aps->nextlen, aps->next);
+}
+
+int
+aps_command(struct aps *aps, int s)
+{
+ char *end;
+ char buf[AP_LINE_MAX];
+ int argc;
+ struct client *c;
+ char *argv[AP_ARGV_MAX];
+ int i;
+ int len;
+ struct command {
+ char *name;
+ char *(*func)(struct aps *, int, int, char **);
+ } commands[] = {
+ { "add", aps_add },
+ { "list", aps_list },
+ { "name", aps_name },
+ { "next", aps_next },
+ { "pause", aps_pause },
+ { "play", aps_play },
+ { "remove", aps_remove },
+ { "seek", aps_seek },
+ { "stop", aps_stop },
+ { "toggle", aps_toggle }
+ };
+
+ c = &aps->clients[s];
+ if (c->request.len == sizeof(c->request.buf)) {
+ c->request.len = 0;
+ return resp_finish(aps, s, strerror(EMSGSIZE));
+ }
+
+ len = recv(s, c->request.buf + c->request.len, LEN(c->request.buf) - c->request.len, 0);
+ if (len == -1)
+ return 1;
+
+ end = memchr(c->request.buf + c->request.len, '\n', len);
+ c->request.len += len;
+ if (end == NULL)
+ return 0; /* not a full command yet */
+
+ *end = 0;
+ len = end - c->request.buf + 1;
+ memcpy(buf, c->request.buf, len);
+ memmove(c->request.buf, c->request.buf + len, c->request.len - len);
+ c->request.len -= len;
+
+ argc = split(argv, LEN(argv), buf, AP_ARG_SEPS);
+ if (!argc)
+ return resp_finish(aps, s, "No command");
+ if (argc < 0)
+ return resp_finish(aps, s, strerror(E2BIG));
+
+ for (i = 0; i < LEN(commands); ++i) {
+ if (strcmp(*argv, commands[i].name) == 0)
+ return resp_finish(aps, s,
+ commands[i].func(aps, s, argc, argv));
+ }
+
+ return resp_finish(aps, s, "Command not found");
+}
diff --git a/command.h b/aps/command.h
diff --git a/aps/mkfile b/aps/mkfile
@@ -0,0 +1,16 @@
+# Copyright 2021 Jacob R. Edwards
+
+name = aps
+src = aps.c command.c player.c queue.c response.c util.c
+obj = ${src:%.c=%.o}
+
+cppflags = -I../lib
+ldflags = -L../lib
+ldlibs = -lap
+
+all:V: $name
+
+< ../mk/config.mk
+< ../mk/clean.mk
+< ../mk/obj.mk
+< ../mk/prog.mk
diff --git a/player.c b/aps/player.c
diff --git a/player.h b/aps/player.h
diff --git a/queue.c b/aps/queue.c
diff --git a/queue.h b/aps/queue.h
diff --git a/aps/response.c b/aps/response.c
@@ -0,0 +1,117 @@
+/* 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 <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ap.h>
+
+#include "player.h"
+#include "queue.h"
+#include "response.h"
+#include "util.h"
+
+#include "aps.h"
+
+int
+resp_enlarge(struct aps *aps, int fd, unsigned int more)
+{
+ struct response *resp;
+ unsigned int newsiz;
+ void *tmp;
+
+ resp = &aps->clients[fd].response;
+ if (resp->len + more < resp->len)
+ ERET(EOVERFLOW);
+
+ newsiz = (resp->siz ? resp->siz * 2 : BUFSIZ);
+ while (newsiz < resp->len + more) {
+ if (newsiz *= 2 < resp->siz)
+ ERET(EOVERFLOW);
+ }
+
+ tmp = realloc(resp->buf, newsiz);
+ if (tmp == NULL) {
+ resp_free(aps, fd);
+ return 1;
+ }
+
+ resp->buf = tmp;
+ resp->siz = newsiz;
+ return 0;
+}
+
+int
+resp_add(struct aps *aps, int fd, void *data, unsigned int len)
+{
+ struct response *resp;
+
+ resp = &aps->clients[fd].response;
+ if (resp->len + len > resp->siz && resp_enlarge(aps, fd, len))
+ return 1;
+
+ memcpy(resp->buf + resp->len, data, len);
+ resp->len += len;
+ return 0;
+}
+
+int
+resp_send(struct aps *aps, int fd)
+{
+ ssize_t n;
+ struct response *resp;
+
+ resp = &aps->clients[fd].response;
+ if (!resp->lock || resp->len - resp->sent == 0)
+ return 1;
+
+ n = send(fd, resp->buf + resp->sent, resp->len - resp->sent,
+ MSG_NOSIGNAL);
+ switch (n) {
+ case -1:
+ return 1;
+ case 0:
+ ERET(ECONNRESET);
+ default:
+ if (resp->sent += n == resp->len)
+ resp_free(aps, fd);
+ return 0;
+ }
+}
+
+void
+resp_end(struct aps *aps, int fd)
+{
+ aps->clients[fd].response.lock = 1;
+}
+
+void
+resp_free(struct aps *aps, int fd)
+{
+ struct response *resp;
+
+ resp = &aps->clients[fd].response;
+ free(resp->buf);
+ memset(resp, 0, sizeof(*resp));
+}
diff --git a/response.h b/aps/response.h
diff --git a/util.c b/aps/util.c
diff --git a/util.h b/aps/util.h
diff --git a/command.c b/command.c
@@ -1,360 +0,0 @@
-/* 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 <ctype.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <limits.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "ap.h"
-#include "apcon.h"
-#include "player.h"
-#include "queue.h"
-#include "response.h"
-#include "util.h"
-
-#include "aps.h"
-
-static char *earg = "Invalid number of arguments";
-static char *enotfound = "Not found";
-static char *eposition = "No position in queue";
-static char *etoofew = "Too few arguments";
-
-int
-resp_finish(struct aps *aps, int s, char *error)
-{
- char buf[AP_LINE_MAX];
- int len;
-
- if (error) {
- len = snprintf(buf, sizeof(buf), "error: %s\n", error);
- } else {
- len = 3;
- memcpy(buf, "ok\n", len);
- }
-
- if (len >= sizeof(buf))
- ERET(EMSGSIZE);
- if (resp_add(aps, s, buf, len))
- return 1;
- resp_end(aps, s);
- return 0;
-}
-
-int
-resp_additem(struct aps *aps, int s, char *item)
-{
- char buf[AP_LINE_MAX];
- int n;
-
- n = snprintf(buf, sizeof(buf), "%s\n", item);
- if (n >= sizeof(buf))
- ERET(EMSGSIZE);
- return resp_add(aps, s, buf, n);
-}
-
-int
-match(char *pattern, struct item *item)
-{
- return fnmatch(pattern, item->path, 0) == 0;
-}
-
-struct item *
-nextmatch(struct item *(*incr)(struct item *), struct item *item,
- char **patterns, int len, int noneall)
-{
- int i;
-
- if (len == 0 || !item)
- return (noneall ? item : NULL);
- for (; item; item = incr(item)) {
- for (i = 0; i < len; ++i) {
- if (match(patterns[i], item))
- return item;
- }
- }
- return item;
-}
-
-char *
-aps_add(struct aps *aps, int s, int argc, char **argv)
-{
- int i;
-
- for (i = 1; i < argc; ++i) {
- if (queue_add(&aps->queue, argv[i]))
- return strerror(errno);
- }
- return NULL;
-}
-
-char *
-aps_remove(struct aps *aps, int s, int argc, char **argv)
-{
- struct item *item, *next;
-
- if (argc == 1) {
- if (aps->queue.pos == NULL)
- return eposition;
- queue_remove(&aps->queue, aps->queue.pos);
- }
-
- next = aps->queue.head;
- while ((item = nextmatch(item_next, next, argv + 1, argc - 1, 0))) {
- next = item->next;
- queue_remove(&aps->queue, item);
- }
-
- return NULL;
-}
-
-char *
-aps_list(struct aps *aps, int s, int argc, char **argv)
-{
- struct item *item;
-
- item = aps->queue.head;
- while ((item = nextmatch(item_next, item, argv + 1, argc - 1, 1))) {
- if (resp_additem(aps, s, item->path))
- return strerror(errno);
- item = item->next;
- }
-
- return NULL;
-}
-
-struct item *
-findnum(struct item *(*incr)(struct item *), struct item *item, char *num,
- char **err)
-{
- int n;
-
- n = strtonum(num, 0, INT_MAX, err);
- if (*err)
- return NULL;
- *err = enotfound;
- return item_seek(incr, item, n);
-}
-
-struct item *
-findpat(struct item *(*incr)(struct item *), struct item *item,
- char **patterns, int len, char **err)
-{
- *err = enotfound;
- return nextmatch(incr, item, patterns, len, 0);
-}
-
-struct item *
-find(struct aps *aps, int argc, char **argv, char **err)
-{
- char *e;
- struct item *(*incr)(struct item *);
- struct item *item;
-
- ++argv;
- --argc;
- if (argc < 1) {
-earg:
- *err = earg;
- return NULL;
- }
-
- incr = item_next;
- item = aps->queue.pos;
- if (argc > 1 && strchr("+-^", **argv) && !argv[0][1]) {
- switch (**argv) {
- case '-':
- incr = item_prev;
- break;
- case '^':
- item = aps->queue.head;
- break;
- }
- ++argv;
- --argc;
- }
-
- if (!isdigit(**argv)) {
- return findpat(incr, incr(item), argv, argc, err);
- } else {
- if (argc != 1)
- goto earg;
- return findnum(incr, item, *argv, err);
- }
-}
-
-char *
-aps_seek(struct aps *aps, int s, int argc, char **argv)
-{
- char *err;
- struct item *item;
-
- item = find(aps, argc, argv, &err);
- if (item == NULL)
- return err;
- aps->queue.pos = item;
- return NULL;
-}
-
-char *
-aps_play(struct aps *aps, int s, int argc, char **argv)
-{
- char *err;
-
- if (argc <= 1) {
- if (aps->queue.pos == NULL)
- return eposition;
- } else if ((err = aps_seek(aps, s, argc, argv))) {
- return err;
- }
-
- if (pplay(&aps->player, aps->queue.pos->path))
- return strerror(errno);
- return NULL;
-}
-
-char *
-aps_pause(struct aps *aps, int s, int argc, char **argv)
-{
- if (psuspend(&aps->player))
- return strerror(errno);
- return NULL;
-}
-
-char *
-aps_stop(struct aps *aps, int s, int argc, char **argv)
-{
- if (pstop(&aps->player))
- return strerror(errno);
- return NULL;
-}
-
-char *
-aps_toggle(struct aps *aps, int s, int argc, char **argv)
-{
- if (ptoggle(&aps->player))
- return strerror(errno);
- return NULL;
-}
-
-char *
-aps_name(struct aps *aps, int s, int argc, char **argv)
-{
- struct item *item;
- char *err;
-
- if (argc < 2)
- item = aps->queue.pos;
- else
- item = find(aps, argc, argv, &err);
- if (item == NULL)
- return err;
-
- if (resp_additem(aps, s, item->path))
- return strerror(errno);
- return NULL;
-}
-
-char *
-aps_next(struct aps *aps, int s, int argc, char **argv)
-{
- int i;
-
- if (argc > 1) {
- for (i = 0; i < argc; ++i) {
- free(aps->next[i]);
- aps->next[i] = strdup(argv[i]);
- if (aps->next[i] == NULL)
- return strerror(errno);
- }
- aps->nextlen = i;
- return NULL;
- }
-
- pstop(&aps->player);
- return aps_play(aps, -1, aps->nextlen, aps->next);
-}
-
-int
-aps_command(struct aps *aps, int s)
-{
- char *end;
- char buf[AP_LINE_MAX];
- int argc;
- struct client *c;
- char *argv[AP_ARGV_MAX];
- int i;
- int len;
- struct command {
- char *name;
- char *(*func)(struct aps *, int, int, char **);
- } commands[] = {
- { "add", aps_add },
- { "list", aps_list },
- { "name", aps_name },
- { "next", aps_next },
- { "pause", aps_pause },
- { "play", aps_play },
- { "remove", aps_remove },
- { "seek", aps_seek },
- { "stop", aps_stop },
- { "toggle", aps_toggle }
- };
-
- c = &aps->clients[s];
- if (c->request.len == sizeof(c->request.buf)) {
- c->request.len = 0;
- return resp_finish(aps, s, strerror(EMSGSIZE));
- }
-
- len = recv(s, c->request.buf + c->request.len, LEN(c->request.buf) - c->request.len, 0);
- if (len == -1)
- return 1;
-
- end = memchr(c->request.buf + c->request.len, '\n', len);
- c->request.len += len;
- if (end == NULL)
- return 0; /* not a full command yet */
-
- *end = 0;
- len = end - c->request.buf + 1;
- memcpy(buf, c->request.buf, len);
- memmove(c->request.buf, c->request.buf + len, c->request.len - len);
- c->request.len -= len;
-
- argc = split(argv, LEN(argv), buf, argseps);
- if (!argc)
- return resp_finish(aps, s, "No command");
- if (argc < 0)
- return resp_finish(aps, s, strerror(E2BIG));
-
- for (i = 0; i < LEN(commands); ++i) {
- if (strcmp(*argv, commands[i].name) == 0)
- return resp_finish(aps, s,
- commands[i].func(aps, s, argc, argv));
- }
-
- return resp_finish(aps, s, "Command not found");
-}
diff --git a/config.def.h b/config.def.h
@@ -1,11 +0,0 @@
-static char *player[] = {
- /* "" = path */
- /* prog, arg, ... */
- "ffplay", "apsplayer", "-loglevel", "error", "-nodisp", "-autoexit", "", NULL
-};
-
-static char *next[] = {
- "config.h", "+", "1"
-};
-
-static int timeout = 250;
diff --git a/lib/ap.h b/lib/ap.h
@@ -0,0 +1,6 @@
+#define AP_LINE_MAX (PATH_MAX * 2)
+#define AP_ARGV_MAX 128
+#define AP_ARG_SEPS "\t"
+
+#include "sock.h"
+#include "apcon.h"
diff --git a/lib/apcon.c b/lib/apcon.c
@@ -0,0 +1,64 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "apcon.h"
+#include "sock.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);
+ if (apc->path == NULL)
+ return 1;
+
+ apc->s = sopen(apc->path, init, SOCK_STREAM | flags);
+ if (apc->s == -1) {
+ free(apc->path);
+ return 1;
+ }
+
+ apc->init = init;
+ return 0;
+}
+
+void
+apcon_close(struct apcon *apc)
+{
+ sclose(apc->s);
+ if (apc->init == bind)
+ unlink(apc->path);
+ free(apc->path);
+}
diff --git a/apcon.h b/lib/apcon.h
diff --git a/lib/libap.a b/lib/libap.a
Binary files differ.
diff --git a/lib/mkfile b/lib/mkfile
@@ -0,0 +1,12 @@
+# Copyright 2021 Jacob R. Edwards
+
+name = libap.a
+src = apcon.c sock.c
+obj = ${src:%.c=%.o}
+
+all:V: $name
+
+< ../mk/config.mk
+< ../mk/clean.mk
+< ../mk/obj.mk
+< ../mk/lib.mk
diff --git a/sock.c b/lib/sock.c
diff --git a/sock.h b/lib/sock.h
diff --git a/mk/clean.mk b/mk/clean.mk
@@ -0,0 +1,4 @@
+# Copyright 2021 Jacob R. Edwards
+
+clean:V:
+ rm -f $name $obj
diff --git a/mk/config.mk b/mk/config.mk
@@ -0,0 +1,12 @@
+# Copyright 2021 Jacob R. Edwards
+
+ar = ar
+cc = tcc
+
+cflags = $cflags -Wall -Wno-write-strings -static
+cppflags = $cppflags -I/usr/include
+ldflags = $ldflags -L/usr/lib
+ldlibs = $ldlibs -lc
+
+prefix = /usr/local
+manprefix = $prefix/man
diff --git a/mk/lib.mk b/mk/lib.mk
@@ -0,0 +1,4 @@
+# Copyright 2021 Jacob R. Edwards
+
+$name: $obj
+ $ar rcs $target $newprereq
diff --git a/mk/obj.mk b/mk/obj.mk
@@ -0,0 +1,4 @@
+# Copyright 2021 Jacob R. Edwards
+
+%.o: %.c
+ $cc $cppflags $cflags -c -o $stem.o $stem.c
diff --git a/mk/prog.mk b/mk/prog.mk
@@ -0,0 +1,12 @@
+# Copyright 2021 Jacob R. Edwards
+
+$name: $obj
+ $cc $ldflags -o $target $prereq $ldlibs
+
+install:V: $name
+ cp -f $name $prefix/bin
+ cp -f $name.1 $manprefix/man1
+
+uninstall:V:
+ rm -f $prefix/bin/$name
+ rm -f $manprefix/man1/$name.1
diff --git a/mkfile b/mkfile
@@ -1,40 +1,10 @@
# Copyright 2021 Jacob R. Edwards
-cc = tcc
-cflags = -Wall -Wno-write-strings -static
-cppflags = -I/usr/include
-ldflags = -L/usr/lib
-ldlibs = -lc
+subdirs = lib aps apc
+targets = install uninstall clean
-prefix = /usr/local
-
-names = aps apc
-src = sock.c apcon.c util.c command.c queue.c player.c response.c
-
-mainobj = ${names:%=%.o}
-obj = ${src:%.c=%.o}
-
-all:V: $names
-
-%.o: %.c
- $cc $cppflags $cflags -c -o $stem.o $stem.c
-
-config.h: config.def.h
- cp $prereq $target
-
-$mainobj $obj: config.h
-
-$names: $mainobj $obj
- for t in $target
+$targets:
+ for dir in $subdirs
do
- $cc $ldflags -o $t $t.o $obj $ldlibs
+ (cd $dir && mk $MKFLAGS $MKARGS)
done
-
-clean:V:
- rm -f $names $mainobj $obj
-
-install:V: $names
- cp -f $names $prefix/bin
-
-uninstall:V:
- (cd $prefix/bin && rm -f $names)
diff --git a/response.c b/response.c
@@ -1,117 +0,0 @@
-/* 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 <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ap.h"
-#include "apcon.h"
-#include "player.h"
-#include "queue.h"
-#include "response.h"
-#include "util.h"
-
-#include "aps.h"
-
-int
-resp_enlarge(struct aps *aps, int fd, unsigned int more)
-{
- struct response *resp;
- unsigned int newsiz;
- void *tmp;
-
- resp = &aps->clients[fd].response;
- if (resp->len + more < resp->len)
- ERET(EOVERFLOW);
-
- newsiz = (resp->siz ? resp->siz * 2 : BUFSIZ);
- while (newsiz < resp->len + more) {
- if (newsiz *= 2 < resp->siz)
- ERET(EOVERFLOW);
- }
-
- tmp = realloc(resp->buf, newsiz);
- if (tmp == NULL) {
- resp_free(aps, fd);
- return 1;
- }
-
- resp->buf = tmp;
- resp->siz = newsiz;
- return 0;
-}
-
-int
-resp_add(struct aps *aps, int fd, void *data, unsigned int len)
-{
- struct response *resp;
-
- resp = &aps->clients[fd].response;
- if (resp->len + len > resp->siz && resp_enlarge(aps, fd, len))
- return 1;
-
- memcpy(resp->buf + resp->len, data, len);
- resp->len += len;
- return 0;
-}
-
-int
-resp_send(struct aps *aps, int fd)
-{
- ssize_t n;
- struct response *resp;
-
- resp = &aps->clients[fd].response;
- if (!resp->lock || resp->len - resp->sent == 0)
- return 1;
-
- n = send(fd, resp->buf + resp->sent, resp->len - resp->sent,
- MSG_NOSIGNAL);
- switch (n) {
- case -1:
- return 1;
- case 0:
- ERET(ECONNRESET);
- default:
- if (resp->sent += n == resp->len)
- resp_free(aps, fd);
- return 0;
- }
-}
-
-void
-resp_end(struct aps *aps, int fd)
-{
- aps->clients[fd].response.lock = 1;
-}
-
-void
-resp_free(struct aps *aps, int fd)
-{
- struct response *resp;
-
- resp = &aps->clients[fd].response;
- free(resp->buf);
- memset(resp, 0, sizeof(*resp));
-}