1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>
#include "line-splitter.h"
namespace config {
namespace sentinel {
LineSplitter::LineSplitter(int fd)
: _fd(fd),
_size(8192),
_buffer(static_cast<char *>(malloc(_size))),
_readPos(0),
_writePos(0),
_eof(false)
{
}
LineSplitter::~LineSplitter()
{
free(_buffer);
}
bool
LineSplitter::resize()
{
_size = _size * 2;
_buffer = static_cast<char *>(realloc(_buffer, _size));
return (_buffer != nullptr);
}
bool
LineSplitter::fill()
{
// Check if we have read to end
int leftToWrite = _writePos - _readPos;
if (leftToWrite == 0) {
_writePos = 0;
_readPos = 0;
} else if (_readPos > 0) { // Move to front
memmove(_buffer, &_buffer[_readPos], leftToWrite);
_writePos -= _readPos;
_readPos = 0;
}
// If buffer is full, resize it
if (_writePos >= _size) {
if (!resize()) {
_eof = true;
shutdown(_fd, SHUT_RD);
return false;
}
}
int readLen = read(_fd, &_buffer[_writePos], _size - _writePos);
if (readLen == -1) {
if (errno != EINTR && errno != EAGAIN) {
_eof = true;
}
} else if (readLen == 0) {
_eof = true;
} else {
_writePos += readLen;
}
return readLen > 0;
}
char *
LineSplitter::getLine()
{
do {
int bufLen = _writePos - _readPos;
if (bufLen > 0) {
char *start = &_buffer[_readPos];
char *end = static_cast<char *>(memchr(start, '\n', bufLen));
if (_eof && !end) {
if (_writePos < _size) {
end = &_buffer[_writePos]; // pretend last byte sent was followed by \n
} else {
end = &_buffer[_writePos-1]; // pretend last byte sent was \n
}
}
if (end) {
*end = '\0';
if (end - start > 0 && end[-1] == '\r') {
// Get rid of carriage return as well.
end[-1] = '\0';
}
_readPos = (end - _buffer) + 1;
return start;
}
}
} while (!_eof && fill());
return nullptr;
}
} // end namespace config::sentinel
} // end namespace config
|