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 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 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 38 uninit_line_buffer(struct line_buffer &buffer) 39 { 40 free(buffer.buffer); 41 return B_OK; 42 } 43 44 45 int32 46 line_buffer_readable(struct line_buffer &buffer) 47 { 48 return buffer.in; 49 } 50 51 52 int32 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 73 line_buffer_writable(struct line_buffer &buffer) 74 { 75 return buffer.size - buffer.in; 76 } 77 78 79 ssize_t 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 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 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