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