1 /*
2  * reimplementation of Daniel Bernstein's buffer library.
3  * placed in the public domain by Uwe Ohse, uwe@ohse.de.
4  */
5 #include "buffer.h"
6 #include "byte.h"
7 #include "error.h"
8 
9 #define READPOS(b) ((b)->buf+(b)->len)
10 
11 static int
do_op(buffer_op op,int fd,char * buf,unsigned int len)12 do_op (buffer_op op, int fd, char *buf, unsigned int len)
13 {
14 	while (1) {
15 		int r;
16 		r = op (fd, buf, len);
17 		if (r == -1)
18 			if (errno == error_intr)
19 				continue;
20 		/* EAGAIN? */
21 		return r;
22 	}
23 }
24 
25 static int
copy2user(buffer * b,char * buf,unsigned int len)26 copy2user (buffer * b, char *buf, unsigned int len)
27 {
28 	if (len > b->pos)
29 		len = b->pos;
30 	b->pos -= len;
31 	byte_copy (buf, len, READPOS(b));
32 	b->len += len;
33 	return len;
34 }
35 
36 int
buffer_feed(buffer * b)37 buffer_feed (buffer * b)
38 {
39 	int r;
40 
41 /* If the string is nonempty, buffer_feed returns the length of the
42  * string. */
43 	if (b->pos)
44 		return b->pos;
45 
46 /* If the string is empty, buffer_feed uses the read operation to
47  * feed data into the string; it then returns the new length of the
48  * string, or 0 for end of input, or -1 for error. */
49 	r = do_op (b->op, b->fd, b->buf, b->len);
50 	if (r <= 0)
51 		return r;
52 	b->pos = r;
53 	b->len -= r;
54 /* Note: this strange construction is needed because DJB didn't
55  * include the buffer size in struct buffer */
56 	if (b->len > 0)
57 		byte_copyr (READPOS(b), r, b->buf);
58 	return r;
59 }
60 
61 char *
buffer_peek(buffer * b)62 buffer_peek (buffer * b)
63 {
64 	return READPOS(b);
65 }
66 
67 /* "skip this many bytes" */
68 void
buffer_seek(buffer * b,unsigned int len)69 buffer_seek(buffer *b,unsigned int len)
70 {
71   b->len += len;
72   b->pos -= len;
73 }
74 
75 int
buffer_get(buffer * b,char * buf,unsigned int len)76 buffer_get (buffer * b, char *buf, unsigned int len)
77 {
78 	int ret;
79 /* Normally buffer_get copies data to x[0], x[1], ..., x[len-1] from the
80  * beginning of a string stored in preallocated space; removes these len
81  * bytes from the string; and returns len.
82  * If, however, the string has fewer than len (but more than 0) bytes,
83  * buffer_get copies only that many bytes, and returns that number.
84  * If the string is empty, buffer_get first uses a read operation to feed
85  * data into the string. The read operation may indicate end of input, in
86  * which case buffer_get returns 0; or a read error, in which case
87  * buffer_get returns -1, setting errno approporiately. */
88 
89 	/* fewer than len, but more than 0 */
90 	if (b->pos)
91 		return copy2user (b, buf, len);
92 	/* buffer too small, read directly */
93 	if (b->len <= len)
94 		return do_op (b->op, b->fd, buf, len);
95 	/* "read operation" to feed data into the string */
96 	ret = buffer_feed (b);
97 	if (ret <= 0)
98 		return ret;
99 	return copy2user (b, buf, len);
100 }
101 
102 /* undocumented interface: like _get, but reads one block max. */
103 int
buffer_bget(buffer * b,char * buf,unsigned int len)104 buffer_bget (buffer * b, char *buf, unsigned int len)
105 {
106 	int ret;
107 
108 	if (b->pos > 0)
109 		return copy2user (b, buf, len);
110 	if (b->len <= len)
111 		return do_op (b->op, b->fd, buf, b->len);
112 	ret = buffer_feed (b);
113 	if (ret <= 0)
114 		return ret;
115 	return copy2user (b, buf, len);
116 }
117