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