ap

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

commit 1965101c60cc1378f44274a5b0c02f57b171fe75
parent 644120595cff7b1648ebdd7b8750e4c94fea5c10
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Tue, 13 Jul 2021 20:56:54 -0700

Rework ap server queue and commands

- Simplify queue

  The queue is now a simple list, the beginning of which is the
  position in it.  This makes searches through the queue pass every
  item naturally without implementing a wrapping search.

- Sync player and queue

  To keep the player and queue in sync, a set of functions were
  added to manage it as defined in 'queue.c'.

  This makes usage less confusing preventing cases such that the
  player is running yet there are no items in the queue.

- Omit command names

  While there are cases where access to the command name would be
  useful, I don't plan on using them so, as it makes the logic
  easier to understand, command names are now omitted.

- Limit command.c to commands

  Far too many large and complex helper functions were previously
  defined in command.c. They are now moved to more appropriate
  locations.

- Add prev command

Diffstat:
Maps/aps.c | 8++++----
Maps/aps.h | 4++--
Maps/buf.c | 7++++---
Maps/command.c | 233+++++++++++++++++++++----------------------------------------------------------
Maps/config.h | 2+-
Aaps/find.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aaps/find.h | 8++++++++
Aaps/item.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aaps/item.h | 12++++++++++++
Aaps/match.c | 36++++++++++++++++++++++++++++++++++++
Aaps/match.h | 2++
Maps/mkfile | 2+-
Maps/player.c | 40++++++++++++++++++++++++++--------------
Maps/queue.c | 105+++++++++++++++++++------------------------------------------------------------
Maps/queue.h | 24+++---------------------
Maps/response.c | 46+++++++++++++++++++++++++++++++++++++++++++---
Maps/response.h | 2++
Maps/util.h | 2--
18 files changed, 433 insertions(+), 304 deletions(-)

diff --git a/aps/aps.c b/aps/aps.c @@ -17,8 +17,6 @@ */ #include <sys/socket.h> -#include <sys/un.h> - #include <sys/wait.h> #include <errno.h> @@ -27,8 +25,10 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> + +#ifdef __OpenBSD__ #include <unistd.h> +#endif #include "aps.h" #include "command.h" @@ -139,7 +139,7 @@ int run(struct aps *aps) { while (!aps->close) { - if (!aps->player.state && aps->queue.pos) + if (!aps->player.state && aps->queue) aps_next(aps, -1, 0, NULL); if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR) return 1; diff --git a/aps/aps.h b/aps/aps.h @@ -3,8 +3,8 @@ struct aps; #include "buf.h" +#include "item.h" #include "player.h" -#include "queue.h" #include "response.h" struct aps { @@ -20,5 +20,5 @@ struct aps { } clients[OPEN_MAX]; struct player player; struct pollfd pfds[OPEN_MAX]; - struct queue queue; + struct item *queue; }; diff --git a/aps/buf.c b/aps/buf.c @@ -21,7 +21,6 @@ #include <string.h> #include "buf.h" -#include "util.h" struct buf * bufnew(void) @@ -43,8 +42,10 @@ bufresize(struct buf *buf, unsigned int newsize) { char *tmp; - if (buf == NULL || newsize < buf->len) - ERET(EINVAL); + if (buf == NULL || newsize < buf->len) { + errno = EINVAL; + return 1; + } tmp = realloc(buf->data, newsize); if (tmp == NULL) diff --git a/aps/command.c b/aps/command.c @@ -18,17 +18,15 @@ #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 "aps.h" +#include "find.h" +#include "queue.h" #include "split.h" #include "util.h" @@ -36,70 +34,13 @@ static char *earg = "Invalid number of arguments"; static char *enotfound = "Not found"; static char *eposition = "No position in queue"; -int -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 (bufappend(aps->clients[s].resp->buf, buf, len)) - return 1; - - aps->clients[s].resp->lock = 1; - return 0; -} - -int -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 bufappend(aps->clients[s].resp->buf, 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])) + for (i = 0; i < argc; ++i) { + if (queue_add(aps, argv[i])) return strerror(errno); } return NULL; @@ -110,17 +51,19 @@ 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); + if (!argc) { + queue_remove(aps, aps->queue); + return NULL; } - next = aps->queue.head; - while ((item = nextmatch(item_next, next, argv + 1, argc - 1, 0))) { - next = item->next; - queue_remove(&aps->queue, item); - } + item = aps->queue; + while ((item = finddir(findnext, item, aps->queue, argv, argc, 0))) { + next = findnext(item); + if (next == item) + next = NULL; + queue_remove(aps, item); + item = next; + } return NULL; } @@ -130,85 +73,29 @@ 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 (additem(aps, s, item->path)) + item = aps->queue; + while ((item = finddir(findnext, item, aps->queue, argv, argc, 0))) { + if (respadd(aps, s, item->path)) return strerror(errno); - item = item->next; + item = findnext(item); + if (item == aps->queue) + return NULL; } 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) -{ - 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, 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); + item = find(aps->queue, aps->queue, argv, argc, 0); if (item == NULL) - return err; - aps->queue.pos = item; + return enotfound; + + if (queue_set(aps, item)) + return strerror(errno); return NULL; } @@ -217,14 +104,15 @@ 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 (argc) { + err = aps_seek(aps, s, argc, argv); + if (err) + return err; } - if (pplay(&aps->player, aps->queue.pos->path)) + if (aps->queue == NULL) + return eposition; + if (pplay(&aps->player, aps->queue->path)) return strerror(errno); return NULL; } @@ -257,36 +145,23 @@ 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); + item = find(aps->queue, aps->queue, argv, argc, 0); if (item == NULL) - return err; + return enotfound; - if (additem(aps, s, item->path)) + if (respadd(aps, s, item->path)) return strerror(errno); return NULL; } -struct item * -aps_incr(struct aps *aps) -{ - if (aps->nextlen > 1 && strcmp(aps->next[1], "-") == 0) - return item_prev(aps->queue.pos); - else - return item_next(aps->queue.pos); -} - char * aps_next(struct aps *aps, int s, int argc, char **argv) { int i; - struct item *start; + struct item *n; - if (argc > 1) { + if (argc) { for (i = 0; i < argc; ++i) { free(aps->next[i]); aps->next[i] = strdup(argv[i]); @@ -297,10 +172,21 @@ aps_next(struct aps *aps, int s, int argc, char **argv) return NULL; } - pstop(&aps->player); - if ((start = aps_incr(aps))) - aps->queue.pos = start; - return aps_play(aps, -1, aps->nextlen, aps->next); + n = find(aps->queue, aps->queue, aps->next, aps->nextlen, 0); + if (n == NULL || queue_set(aps, n)) + return strerror(errno); + return NULL; +} + +char * +aps_prev(struct aps *aps, int s, int argc, char **argv) +{ + struct item *n; + + n = find(aps->queue, aps->queue, aps->next, aps->nextlen, FIND_REVERSE); + if (n == NULL || queue_set(aps, n)) + return strerror(errno); + return NULL; } char * @@ -314,7 +200,7 @@ aps_read(struct aps *aps, int s) if (buf->len == buf->size && bufresize(buf, MAX(buf->size, 128) * 2)) { buf->len = 0; /* TODO: handle error */ - finish(aps, s, strerror(errno)); + respfinish(aps, s, strerror(errno)); return NULL; } @@ -350,6 +236,7 @@ aps_command(struct aps *aps, int s) { "next", aps_next }, { "pause", aps_pause }, { "play", aps_play }, + { "prev", aps_prev }, { "remove", aps_remove }, { "seek", aps_seek }, { "stop", aps_stop }, @@ -367,16 +254,16 @@ aps_command(struct aps *aps, int s) len = split(argv, LEN(argv), bufbuf, AP_ARG_SEPS); if (len == 0) - return finish(aps, s, "No command"); + return respfinish(aps, s, "No command"); if (len < 0) - return finish(aps, s, earg); + return respfinish(aps, s, earg); for (i = 0; i < LEN(commands); ++i) { if (strcmp(*argv, commands[i].name) == 0) { - return finish(aps, s, - commands[i].func(aps, s, len, argv)); + return respfinish(aps, s, + commands[i].func(aps, s, len - 1, argv + 1)); } } - return finish(aps, s, "Command not found"); + return respfinish(aps, s, "Command not found"); } diff --git a/aps/config.h b/aps/config.h @@ -5,7 +5,7 @@ static char *player[] = { }; static char *next[] = { - "config.h", "*" + "config.h", "+1" }; static int timeout = 250; diff --git a/aps/find.c b/aps/find.c @@ -0,0 +1,106 @@ +/* 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 <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "find.h" +#include "item.h" +#include "match.h" + +#define REV(ITEM) (ITEM == findnext ? findprev : findnext) + +struct item * +findnext(struct item *item) +{ + return item->next; +} + +struct item * +findprev(struct item *item) +{ + return item->prev; +} + +struct item * +findnum(struct item *(*incr)(struct item *), struct item *item, struct item *end, + int num) +{ + if (num < 0) { + incr = REV(incr); + num = -num; + } + + while (item && num--) { + if ((item = incr(item)) == end) { + errno = ENOENT; + return NULL; + } + } + return item; +} + +struct item * +finddir(struct item *(*incr)(struct item *), struct item *item, struct item *end, + char **patterns, unsigned int len, unsigned int flags) +{ + long nth; + char *ep; + + if (flags & FIND_REVERSE) + incr = REV(incr); + + if (len == 1) { + nth = strtol(patterns[0], &ep, 10); + if (*ep == '\0') { + if (nth < INT_MIN || nth > INT_MAX) { + errno = EDOM; + return NULL; + } + return findnum(incr, item, end, nth); + } + } + + while (item && !multimatch(item->path, patterns, len)) { + if ((item = incr(item)) == end) { + errno = ENOENT; + return NULL; + } + } + + return item; +} + +struct item * +find(struct item *item, struct item *end, char **patterns, unsigned int len, + unsigned int flags) +{ + struct item *(*incr)(struct item *); + + incr = findnext; + if (len && (strchr("+-", patterns[0][0]) && patterns[0][1] == '\0')) { + if (patterns[0][0] == '-') + incr = findprev; + ++patterns; + --len; + } + + return finddir(incr, item, end, patterns, len, flags); +} diff --git a/aps/find.h b/aps/find.h @@ -0,0 +1,8 @@ +enum findflag { + FIND_REVERSE = 1 +}; + +struct item *findnext(struct item *); +struct item *findprev(struct item *); +struct item *finddir(struct item *(*)(struct item *), struct item *, struct item *, char **, unsigned int, unsigned int); +struct item *find(struct item *, struct item *, char **, unsigned int, unsigned int); diff --git a/aps/item.c b/aps/item.c @@ -0,0 +1,98 @@ +/* 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 <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "item.h" + +struct item * +item_new(char *path) +{ + struct item *item; + + item = calloc(1, sizeof(*item)); + if (item == NULL) + return NULL; + + item->path = strdup(path); + if (item->path == NULL) { + free(item); + return NULL; + } + + return item; +} + +void +item_free(struct item *item) +{ + if (item) { + free(item->path); + free(item); + } +} + +int +item_insert(struct item *list, struct item *item) +{ + if (list == NULL || item == NULL || item->next || item->prev) { + errno = EINVAL; + return 1; + } + + if (list->prev == NULL) { + assert(list->next != NULL); + list->next = list->prev = item; + item->next = item->prev = list; + } else { + list->prev->next = item; + item->prev = list->prev; + item->next = list; + list->prev = item; + } + + return 0; +} + +void +item_unlink(struct item *item) +{ + if (item->prev) + item->prev->next = item->next; + if (item->next) + item->next->prev = item->prev; +} + +struct item * +item_next(struct item *item, struct item *end) +{ + if (item == end) + return NULL; + return item->next; +} + +struct item * +item_prev(struct item *item, struct item *end) +{ + if (item == end) + return NULL; + return item->prev; +} diff --git a/aps/item.h b/aps/item.h @@ -0,0 +1,12 @@ +struct item; + +struct item { + char *path; + struct item *next; + struct item *prev; +}; + +struct item *item_new(char *); +void item_free(struct item *); +int item_insert(struct item *, struct item *); +void item_unlink(struct item *); diff --git a/aps/match.c b/aps/match.c @@ -0,0 +1,36 @@ +/* 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 <fnmatch.h> + +int +match(char *s, char *pattern) +{ + return fnmatch(pattern, s, 0) == 0; +} + +int +multimatch(char *s, char **patterns, unsigned int len) +{ + int i; + + for (i = 0; i < len; ++i) + if (!match(s, patterns[i])) + return 0; + return 1; +} diff --git a/aps/match.h b/aps/match.h @@ -0,0 +1,2 @@ +int match(char *, char *); +int multimatch(char *, char **, unsigned int); diff --git a/aps/mkfile b/aps/mkfile @@ -1,7 +1,7 @@ # Copyright 2021 Jacob R. Edwards name = aps -src = aps.c buf.c command.c player.c queue.c response.c split.c +src = aps.c buf.c command.c find.c item.c match.c player.c queue.c response.c split.c obj = ${src:%.c=%.o} cppflags = -I../lib diff --git a/aps/player.c b/aps/player.c @@ -22,18 +22,18 @@ #include <limits.h> #include <signal.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> #include <unistd.h> #include "player.h" -#include "util.h" int pstart(struct player *p) { - if (p->state & (RUNNING | SUSPENDED)) - ERET(EALREADY); + if (p->state & (RUNNING | SUSPENDED)) { + errno = EALREADY; + return 1; + } p->pid = fork(); if (p->pid < 0) @@ -51,8 +51,10 @@ pstart(struct player *p) int pstop(struct player *p) { - if (p->state == STOPPED) - ERET(EALREADY); + if (p->state == STOPPED) { + errno = EALREADY; + return 1; + } if (p->state & (RUNNING | SUSPENDED) && kill(p->pid, SIGTERM) == -1) return 1; p->state = STOPPED; @@ -62,8 +64,11 @@ pstop(struct player *p) int psuspend(struct player *p) { - if (p->state != RUNNING) - ERET(EINVAL); + if (p->state != RUNNING) { + errno = EINVAL; + return 1; + } + if (kill(p->pid, SIGSTOP) == -1) return 1; p->state = SUSPENDED; @@ -73,8 +78,11 @@ psuspend(struct player *p) int pcontinue(struct player *p) { - if (p->state != SUSPENDED) - ERET(EINVAL); + if (p->state != SUSPENDED) { + errno = EINVAL; + return 1; + } + if (kill(p->pid, SIGCONT) == -1) return 1; p->state = RUNNING; @@ -90,11 +98,15 @@ pplay(struct player *p, char *path) } else if (path && strcmp(p->path, path) != 0) { if (p->state & (RUNNING | SUSPENDED) && pstop(p)) return 1; - if (strlcpy(p->path, path, sizeof(p->path)) >= sizeof(p->path)) - ERET(ENAMETOOLONG); + if (strlcpy(p->path, path, sizeof(p->path)) >= sizeof(p->path)) { + errno = ENAMETOOLONG; + return 1; + } } else { - if (p->state == RUNNING) - ERET(EALREADY); + if (p->state == RUNNING) { + errno = EALREADY; + return 1; + } if (p->state == SUSPENDED) return pcontinue(p); } diff --git a/aps/queue.c b/aps/queue.c @@ -16,106 +16,51 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <errno.h> -#include <stdlib.h> -#include <string.h> +#include <sys/socket.h> -#include "queue.h" +#include <limits.h> +#include <poll.h> +#include <stddef.h> -struct item * -item_new(char *path) -{ - struct item *item; - - item = calloc(1, sizeof(*item)); - if (item == NULL) - return NULL; - - item->path = strdup(path); - if (item->path == NULL) { - free(item); - return NULL; - } - - return item; -} - -void -item_free(struct item *item) -{ - free(item->path); - free(item); -} - -struct item * -item_next(struct item *item) -{ - return item->next; -} - -struct item * -item_prev(struct item *item) -{ - return item->prev; -} +#include "aps.h" int -item_pos(struct item *(*incr)(struct item *), struct item *item) -{ - unsigned int i; - - for (i = -1; item; ++i) - item = incr(item); - return i; -} - -struct item * -item_seek(struct item *(*incr)(struct item *), struct item *item, unsigned int n) +queue_set(struct aps *aps, struct item *item) { - if (item == NULL) - return NULL; - while (n-- && (item = incr(item))) - ; - return item; + aps->queue = item; + if ((aps->player.state != STOPPED && aps->queue) && + (pstop(&aps->player) || pplay(&aps->player, aps->queue->path))) + return 1; + return 0; } int -queue_add(struct queue *q, char *path) +queue_add(struct aps *aps, char *s) { struct item *item; - item = item_new(path); + item = item_new(s); if (item == NULL) return 1; - if (q->head == NULL) { - q->head = q->pos = item; - } else if (q->tail == NULL) { - q->tail = item; - q->head->next = q->tail; - q->tail->prev = q->head; - return 0; - } else { - q->tail->next = item; - item->prev = q->tail; - q->tail = item; + if (aps->queue == NULL) { + queue_set(aps, item); /* ignore player errors */ + } else if (item_insert(aps->queue, item)) { + item_free(item); + return 1; } return 0; } void -queue_remove(struct queue *q, struct item *item) +queue_remove(struct aps *aps, struct item *item) { - if (q->head == item) - q->head = item->next; - if (q->tail == item) - q->tail = item->prev; - if (q->pos == item) - q->pos = item->prev ? item->prev : item->next; - if (item->prev) - item->prev->next = item->next; - if (item->next) - item->next->prev = item->prev; + if (item == NULL) + return; + if (aps->queue == item) + queue_set(aps, item->next == item ? NULL : item->next); + + item_unlink(item); item_free(item); } diff --git a/aps/queue.h b/aps/queue.h @@ -1,21 +1,3 @@ -struct item; - -struct item { - char *path; - struct item *next; - struct item *prev; -}; - -struct queue { - struct item *head; - struct item *pos; - struct item *tail; -}; - -struct item *item_next(struct item *); -struct item *item_prev(struct item *); -int item_pos(struct item *(*)(struct item *), struct item *); -struct item *item_seek(struct item *(*)(struct item *), struct item *, unsigned int); - -int queue_add(struct queue *, char *); -void queue_remove(struct queue *, struct item *); +int queue_set(struct aps *, struct item *); +int queue_add(struct aps *, char *); +void queue_remove(struct aps *, struct item *); diff --git a/aps/response.c b/aps/response.c @@ -21,10 +21,11 @@ #include <errno.h> #include <limits.h> #include <poll.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include "aps.h" -#include "util.h" #define RESP (aps->clients[fd].resp) @@ -51,6 +52,43 @@ respfree(struct aps *aps, int fd) } int +respadd(struct aps *aps, int fd, char *item) +{ + char buf[AP_LINE_MAX]; + int n; + + n = snprintf(buf, sizeof(buf), "%s\n", item); + if (n >= sizeof(buf)) { + errno = EMSGSIZE; + return 1; + } + return bufappend(aps->clients[fd].resp->buf, buf, n); +} + +int +respfinish(struct aps *aps, int fd, char *error) +{ + char buf[AP_LINE_MAX]; + int len; + + if (error) { + len = snprintf(buf, sizeof(buf), "error: %s\n", error); + if (len >= sizeof(buf)) { + errno = EMSGSIZE; + return 1; + } + } else { + len = 3; + memcpy(buf, "ok\n", len); + } + + if (bufappend(aps->clients[fd].resp->buf, buf, len)) + return 1; + aps->clients[fd].resp->lock = 1; + return 0; +} + +int respond(struct aps *aps, int fd) { ssize_t n; @@ -64,8 +102,10 @@ respond(struct aps *aps, int fd) if (n < 0) return 1; - if (n == 0) - ERET(ECONNRESET); + if (n == 0) { + errno = ECONNRESET; + return 1; + } if (resp->sent += n == resp->buf->len) { resp->buf->len = 0; resp->sent = 0; diff --git a/aps/response.h b/aps/response.h @@ -6,4 +6,6 @@ struct response { int respnew(struct aps *, int); void respfree(struct aps *, int); +int respadd(struct aps *, int, char *); +int respfinish(struct aps *, int, char *); int respond(struct aps *, int); diff --git a/aps/util.h b/aps/util.h @@ -1,4 +1,2 @@ -#define ERET(E) { errno = E; return 1; } -#define ERROR(S) (write(2, S, sizeof(S) - 1) != sizeof(S) - 1) #define LEN(X) (sizeof(X) / sizeof(*X)) #define MAX(A,B) (A > B ? A : B)