ap

Queue manager meant to be used as an audio player
git clone git://jacobedwards.org/ap
Log | Files | Refs | README | LICENSE

apc.c (3456B)


      1 /*
      2  * Copyright 2021-2023 Jacob R. Edwards <jacob@jacobedwards.org>
      3  *
      4  * ap -- audio player
      5  *
      6  * This program is free software: you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, either version 3 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include <sys/socket.h>
     21 
     22 #include <limits.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 #ifdef __OpenBSD__
     28 #include <unistd.h>
     29 #else
     30 #define pledge(a,b) (0)
     31 #endif
     32 
     33 static char *ewrite = "Unable to write request";
     34 static char *eread = "Unable to read response";
     35 
     36 #include <ap/client.h>
     37 
     38 static char subchr = '^';
     39 
     40 void
     41 die(char *s)
     42 {
     43 	perror(s);
     44 	exit(1);
     45 }
     46 
     47 int
     48 printline(char *buf)
     49 {
     50 	int status;
     51 	char *word, *bufp;
     52 
     53 	bufp = buf;
     54 	word = apunquote(&buf, NULL);
     55 	if (!word)
     56 		return 1;
     57 
     58 	if (!apfindquote(&buf, NULL))
     59 		status = puts(word) < 0;
     60 	else
     61 		status = puts(bufp) < 0;
     62 	free(word);
     63 
     64 	return status;
     65 }
     66 
     67 int
     68 printresponse(struct apc *apc)
     69 {
     70 	char *buf;
     71 
     72 	while ((buf = apc_read(apc))) {
     73 		if (printline(buf)) {
     74 			free(buf);
     75 			return 1;
     76 		}
     77 		free(buf);
     78 	}
     79 	if (apc->status == NULL)
     80 		return 1;
     81 	if (strcmp(apc->status, "ok") != 0)
     82 		return fprintf(stderr, "%s\n", apc->status) < 0;
     83 	return 0;
     84 
     85 }
     86 
     87 char *
     88 apc_stream(struct apc *apc, FILE *fp)
     89 {
     90 	char *buf;
     91 	size_t size;
     92 	ssize_t len;
     93 	char *err;
     94 
     95 	buf = NULL;
     96 	size = 0;
     97 	err = NULL;
     98 	while (!err && (len = getline(&buf, &size, fp)) >= 0) {
     99 		if (write(apc->con->sock, buf, len) != len)
    100 			err = ewrite;
    101 		else if (printresponse(apc))
    102 			err = eread;
    103 	}
    104 	free(buf);
    105 	if (ferror(stdin))
    106 		return "Unable to read from standard input";
    107 	return err;
    108 }
    109 
    110 /*
    111  * Returns the number of arguments gathered. If negative that many
    112  * were gathered before an error. If LONG_MAX is returned, it may
    113  * have gathered any number of arguments.
    114  */
    115 long
    116 xargs(struct apc *apc, FILE *fp)
    117 {
    118 	char *buf;
    119 	long nargs;
    120 	size_t size;
    121 	ssize_t len;
    122 
    123 	nargs = 0;
    124 	buf = NULL;
    125 	size = 0;
    126 	while ((len = getline(&buf, &size, fp)) >= 0) {
    127 		if (len && buf[len - 1] == '\n')
    128 			buf[--len] = 0;
    129 		if (apc_bufword(apc, buf))
    130 			return -nargs;
    131 		if (nargs < LONG_MAX)
    132 			++nargs;
    133 	}
    134 	free(buf);
    135 	if (ferror(stdin))
    136 		return -nargs;
    137 	return nargs;
    138 }
    139 
    140 int
    141 main(int argc, char *argv[])
    142 {
    143 	char *err;
    144 	int i;
    145 	int insert;
    146 	int status;
    147 	struct apc *apc;
    148 
    149 	apc = apc_new(NULL);
    150 	if (apc == NULL)
    151 		die("Unable to connect to server");
    152 
    153 	if (pledge("stdio", NULL))
    154 		die("pledge");
    155 
    156 	--argc;
    157 	++argv;
    158 
    159 	if (!argc) {
    160 		if ((err = apc_stream(apc, stdin)))
    161 			die(err);
    162 	} else {
    163 		insert = 0;
    164 		if (argv[argc - 1][0] == subchr) {
    165 			++argv[argc - 1];
    166 			if (argv[argc - 1][0] == '\0') {
    167 				insert = 1;
    168 				--argc;
    169 			}
    170 		}
    171 
    172 		for (i = 0; i < argc; ++i)
    173 			if (apc_bufword(apc, argv[i]))
    174 				die(ewrite);
    175 
    176 		if (insert && xargs(apc, stdin) < 1)
    177 			die("Unable to get arguments from stdin");
    178 
    179 		if (apc_write(apc))
    180 			die(ewrite);
    181 		else if (printresponse(apc))
    182 			die(eread);
    183 	}
    184 
    185 	status = (apc->status && strcmp(apc->status, "ok") != 0);
    186 	apc_free(apc);
    187 	return status;
    188 }