1 /*
2 * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "line_buffer.h"
8
9 #include <KernelExport.h>
10 #include <stdlib.h>
11
12
13 status_t
clear_line_buffer(struct line_buffer & buffer)14 clear_line_buffer(struct line_buffer &buffer)
15 {
16 buffer.in = 0;
17 buffer.first = 0;
18 return B_OK;
19 }
20
21
22 status_t
init_line_buffer(struct line_buffer & buffer,size_t size)23 init_line_buffer(struct line_buffer &buffer, size_t size)
24 {
25 clear_line_buffer(buffer);
26
27 buffer.buffer = (char *)malloc(size);
28 if (buffer.buffer == NULL)
29 return B_NO_MEMORY;
30
31 buffer.size = size;
32
33 return B_OK;
34 }
35
36
37 status_t
uninit_line_buffer(struct line_buffer & buffer)38 uninit_line_buffer(struct line_buffer &buffer)
39 {
40 free(buffer.buffer);
41 return B_OK;
42 }
43
44
45 int32
line_buffer_readable(struct line_buffer & buffer)46 line_buffer_readable(struct line_buffer &buffer)
47 {
48 return buffer.in;
49 }
50
51
52 int32
line_buffer_readable_line(struct line_buffer & buffer,char eol,char eof)53 line_buffer_readable_line(struct line_buffer &buffer, char eol, char eof)
54 {
55 size_t size = buffer.in;
56 if (size == 0)
57 return 0;
58
59 // find EOL or EOF char
60 for (size_t i = 0; i < size; i++) {
61 char c = buffer.buffer[(buffer.first + i) % buffer.size];
62 if (c == eol || c == '\n' || c == '\r' || c == eof)
63 return i + 1;
64 }
65
66 // If the buffer is full, but doesn't contain a EOL or EOF, we report the
67 // full size anyway, since otherwise the reader would wait forever.
68 return buffer.in == buffer.size ? buffer.in : 0;
69 }
70
71
72 int32
line_buffer_writable(struct line_buffer & buffer)73 line_buffer_writable(struct line_buffer &buffer)
74 {
75 return buffer.size - buffer.in;
76 }
77
78
79 ssize_t
line_buffer_user_read(struct line_buffer & buffer,char * data,size_t length,char eof,bool * hitEOF)80 line_buffer_user_read(struct line_buffer &buffer, char *data, size_t length,
81 char eof, bool* hitEOF)
82 {
83 size_t available = buffer.in;
84
85 if (length > available)
86 length = available;
87
88 if (length == 0)
89 return 0;
90
91 // check for EOF, if the caller asked us to
92 if (hitEOF) {
93 *hitEOF = false;
94 for (size_t i = 0; i < available; i++) {
95 char c = buffer.buffer[(buffer.first + i) % buffer.size];
96 if (c == eof) {
97 *hitEOF = true;
98 length = i;
99 break;
100 }
101 }
102 }
103
104 ssize_t bytesRead = length;
105
106 if (buffer.first + length < buffer.size) {
107 // simple copy
108 if (user_memcpy(data, buffer.buffer + buffer.first, length) != B_OK)
109 bytesRead = B_BAD_ADDRESS;
110 } else {
111 // need to copy both ends
112 size_t upper = buffer.size - buffer.first;
113 size_t lower = length - upper;
114
115 if (user_memcpy(data, buffer.buffer + buffer.first, upper) != B_OK
116 || user_memcpy(data + upper, buffer.buffer, lower) != B_OK)
117 bytesRead = B_BAD_ADDRESS;
118 }
119
120 if (bytesRead > 0) {
121 buffer.first = (buffer.first + bytesRead) % buffer.size;
122 buffer.in -= bytesRead;
123 }
124
125 // dispose of EOF char
126 if (hitEOF && *hitEOF) {
127 buffer.first = (buffer.first + 1) % buffer.size;
128 buffer.in--;
129 }
130
131 return bytesRead;
132 }
133
134
135 status_t
line_buffer_putc(struct line_buffer & buffer,char c)136 line_buffer_putc(struct line_buffer &buffer, char c)
137 {
138 if (buffer.in == buffer.size)
139 return B_NO_MEMORY;
140
141 buffer.buffer[(buffer.first + buffer.in++) % buffer.size] = c;
142 return B_OK;
143 }
144
145
146 #if 0
147 status_t
148 line_buffer_getc(struct line_buffer &buffer, char *_c)
149 {
150 }
151
152
153 status_t
154 line_buffer_ungetc(struct line_buffer &buffer, char *c)
155 {
156 }
157
158 #endif
159
160
161 bool
line_buffer_tail_getc(struct line_buffer & buffer,char * c)162 line_buffer_tail_getc(struct line_buffer &buffer, char *c)
163 {
164 if (buffer.in == 0)
165 return false;
166
167 *c = buffer.buffer[(buffer.first + --buffer.in) % buffer.size];
168 return true;
169 }
170