buf.c (2934B)
1 /* 2 * Copyright 2021, 2022 Jacob R. Edwards 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 <errno.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <stdint.h> 24 #include <ctype.h> 25 26 #include <ap/buf.h> 27 #include <ap/quote.h> 28 29 struct buf * 30 bufnew(void) 31 { 32 return calloc(1, sizeof(struct buf)); 33 } 34 35 void 36 buffree(struct buf *buf) 37 { 38 if (buf == NULL) 39 return; 40 free(buf->data); 41 free(buf); 42 } 43 44 int 45 bufresize(struct buf *buf, size_t newsize) 46 { 47 char *tmp; 48 49 if (buf == NULL || newsize < buf->len) { 50 errno = EINVAL; 51 return 1; 52 } 53 54 tmp = realloc(buf->data, newsize); 55 if (tmp == NULL) 56 return 1; 57 58 buf->data = tmp; 59 buf->size = newsize; 60 return 0; 61 } 62 63 int 64 bufenlarge(struct buf *buf, size_t needed) 65 { 66 size_t newsize; 67 68 for (newsize = buf->size ? buf->size : (1024 * 8); 69 newsize != SIZE_MAX && needed > (newsize - buf->len);) { 70 if (newsize > SIZE_MAX / 4) 71 newsize = SIZE_MAX; 72 else 73 newsize *= 4; 74 } 75 76 if (needed > (newsize - buf->len)) { 77 errno = EOVERFLOW; 78 return 1; 79 } 80 if (newsize == buf->size) 81 return 0; 82 return bufresize(buf, newsize); 83 } 84 85 int 86 bufappend(struct buf *buf, void *data, size_t len) 87 { 88 if (buf == NULL || bufenlarge(buf, len)) 89 return 1; 90 memcpy(buf->data + buf->len, data, len); 91 buf->len += len; 92 return 0; 93 } 94 95 int 96 bufshift(struct buf *buf, size_t n) 97 { 98 if (n > buf->len) { 99 errno = EOVERFLOW; 100 return 1; 101 } 102 memmove(buf->data, buf->data + n, buf->len - n); 103 buf->len -= n; 104 return 0; 105 } 106 107 int 108 bufword(struct buf *buf, char *word) 109 { 110 size_t len; 111 112 word = apquote(word, NULL); 113 if (word == NULL) 114 return 1; 115 len = strlen(word); 116 117 if (bufenlarge(buf, len + 1)) { 118 free(word); 119 return 1; 120 } 121 122 if (buf->len && !isspace(buf->data[buf->len - 1])) 123 bufappend(buf, " ", 1); 124 bufappend(buf, word, len); 125 126 free(word); 127 return 0; 128 } 129 130 int 131 bufline(struct buf *buf, char *line) 132 { 133 if (buf->len && buf->data[buf->len - 1] != '\n' && 134 bufappend(buf, "\n", 1)) 135 return 1; 136 137 if (!line) 138 return 0; 139 140 if (bufword(buf, line)) 141 return 1; 142 return bufappend(buf, "\n", 1); 143 } 144 145 int 146 bufgetline(struct buf *buf, char **line) 147 { 148 char *end; 149 size_t len; 150 151 if (!(end = memchr(buf->data, '\n', buf->len))) 152 return 0; 153 154 len = end - buf->data + 1; 155 if (!(*line = malloc(len))) 156 return -1; 157 158 memcpy(*line, buf->data, len - 1); 159 (*line)[len - 1] = 0; 160 bufshift(buf, len); 161 return 1; 162 }