ap

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

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 }