xref: /haiku/src/add-ons/kernel/generic/tty/line_buffer.cpp (revision 91bcf08ee50af0da44d5d8631477e7c08c5e0255)
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