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 }