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
13status_t
14clear_line_buffer(struct line_buffer &buffer)
15{
16	buffer.in = 0;
17	buffer.first = 0;
18	return B_OK;
19}
20
21
22status_t
23init_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
37status_t
38uninit_line_buffer(struct line_buffer &buffer)
39{
40	free(buffer.buffer);
41	return B_OK;
42}
43
44
45int32
46line_buffer_readable(struct line_buffer &buffer)
47{
48	return buffer.in;
49}
50
51
52int32
53line_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
72int32
73line_buffer_writable(struct line_buffer &buffer)
74{
75	return buffer.size - buffer.in;
76}
77
78
79ssize_t
80line_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
135status_t
136line_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
147status_t
148line_buffer_getc(struct line_buffer &buffer, char *_c)
149{
150}
151
152
153status_t
154line_buffer_ungetc(struct line_buffer &buffer, char *c)
155{
156}
157
158#endif
159
160
161bool
162line_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