source: nanovis/trunk/ReadBuffer.cpp @ 4794

Last change on this file since 4794 was 4063, checked in by ldelgass, 6 years ago

Remove some more Rappture deps from nanovis

  • Property svn:eol-style set to native
File size: 5.1 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2012  HUBzero Foundation, LLC
4 *
5 * Author: George A. Howlett <gah@purdue.edu>
6 */
7
8#include <cstdlib>
9#include <cerrno>
10#include <cstdio>
11#include <unistd.h>
12#include <cstring>
13
14#include <RpBuffer.h>
15
16#include "ReadBuffer.h"
17#include "Trace.h"
18
19using namespace nv;
20
21/**
22 * \param[in] fd File descriptor to read
23 * \param[in] bufferSize Block size to use in internal buffer
24 */
25ReadBuffer::ReadBuffer(int fd, size_t bufferSize) :
26    _bufferSize(bufferSize),
27    _fd(fd),
28    _lastStatus(OK)
29{
30    _bytes = new unsigned char [_bufferSize];
31    flush();
32}
33
34ReadBuffer::~ReadBuffer()
35{
36    TRACE("Deleting ReadBuffer");
37    delete [] _bytes;
38}
39
40/**
41 * \brief Checks if a new line is currently in the buffer.
42 *
43 * \return the index of the character past the new line.
44 */
45size_t
46ReadBuffer::nextNewLine()
47{
48    /* Check for a newline in the current buffer. */
49    unsigned char *ptr = 
50        (unsigned char *)memchr(_bytes + _mark, '\n', _fill - _mark);
51    if (ptr == NULL)
52        return 0;
53    else
54        return (ptr - _bytes + 1);
55}
56
57/** 
58 * \brief Fills the buffer with available data.
59 *
60 * Any existing data in the buffer is moved to the front of the buffer,
61 * then the channel is read to fill the rest of the buffer.
62 *
63 * \return If an error occur when reading the channel, then ERROR is
64 * returned. ENDFILE is returned on EOF.  If the buffer can't be filled,
65 * then CONTINUE is returned.
66 */
67ReadBuffer::BufferStatus
68ReadBuffer::doFill()
69{
70    //TRACE("Enter, mark: %lu fill: %lu", _mark, _fill);
71    if (_mark >= _fill) {
72        flush();                        /* Fully consumed buffer */
73    }
74    if (_mark > 0) {
75        /* Some data has been consumed. Move the unconsumed data to the front
76         * of the buffer. */
77        TRACE("memmove %lu bytes", _fill-_mark);
78        memmove(_bytes, _bytes + _mark, _fill - _mark);
79        _fill -= _mark;
80        _mark = 0;
81    }
82    ssize_t numRead;
83    size_t bytesLeft;
84
85    bytesLeft = _bufferSize - _fill;
86    //TRACE("going to read %lu bytes", bytesLeft);
87    numRead = read(_fd, _bytes + _fill, bytesLeft);
88    if (numRead == 0) {
89        /* EOF */
90        TRACE("EOF found reading buffer");
91        return ReadBuffer::ENDFILE;
92    }
93    if (numRead < 0) {
94        if (errno != EAGAIN) {
95            ERROR("error reading buffer: %s", strerror(errno));
96            return ReadBuffer::ERROR;
97        }
98        TRACE("Short read for buffer");
99        return ReadBuffer::CONTINUE;
100    }
101    _fill += numRead;
102    //TRACE("Read %lu bytes", numRead);
103    return ((size_t)numRead == bytesLeft) 
104        ? ReadBuffer::OK : ReadBuffer::CONTINUE;
105}
106
107/**
108 * \brief Read the requested number of bytes from the buffer.
109
110 * Fails if the requested number of bytes are not immediately
111 * available. Never should be short.
112 */
113ReadBuffer::BufferStatus
114ReadBuffer::followingData(unsigned char *out, size_t numBytes)
115{
116    TRACE("Enter");
117    while (numBytes > 0) {
118        size_t bytesLeft;
119
120        bytesLeft = _fill - _mark;
121        if (bytesLeft > 0) {
122            int size;
123
124            /* Pull bytes out of the buffer, updating the mark. */
125            size = (bytesLeft >  numBytes) ? numBytes : bytesLeft;
126            memcpy(out, _bytes + _mark, size);
127            _mark += size;
128            numBytes -= size;
129            out += size;
130        }
131        if (numBytes == 0) {
132            /* Received requested # bytes. */
133            return ReadBuffer::OK;
134        }
135        /* Didn't get enough bytes, need to read some more. */
136        _lastStatus = doFill();
137        if (_lastStatus == ReadBuffer::ERROR ||
138            _lastStatus == ReadBuffer::ENDFILE) {
139            return _lastStatus;
140        }
141    }
142    return ReadBuffer::OK;
143}
144
145/**
146 * \brief Returns the next available line (terminated by a newline)
147 *
148 * If insufficient data is in the buffer, then the channel is
149 * read for more data.  If reading the channel results in a
150 * short read, CONTINUE is returned and *numBytesPtr is set to 0.
151 */
152ReadBuffer::BufferStatus
153ReadBuffer::getLine(size_t *numBytesPtr, unsigned char **bytesPtr)
154{
155    TRACE("Enter");
156    *numBytesPtr = 0;
157    *bytesPtr = NULL;
158
159    _lastStatus = ReadBuffer::OK;
160    for (;;) {
161        size_t _newline;
162
163        _newline = nextNewLine();
164        if (_newline > 0) {
165            /* Start of the line. */
166            *bytesPtr = _bytes + _mark;
167            /* Number of bytes in the line. */
168            *numBytesPtr = _newline - _mark;
169            _mark = _newline;
170            return ReadBuffer::OK;
171        }
172        /* Couldn't find a newline, so it may be that we need to read some
173         * more. Check first that last read wasn't a short read. */
174        if (_lastStatus == ReadBuffer::CONTINUE) {
175            /* No complete line just yet. */
176            return ReadBuffer::CONTINUE;
177        }
178        /* Try to add more data to the buffer. */
179        _lastStatus = doFill();
180        if (_lastStatus == ReadBuffer::ERROR ||
181            _lastStatus == ReadBuffer::ENDFILE) {
182            return _lastStatus;
183        }
184        /* OK or CONTINUE */
185    }
186    return ReadBuffer::CONTINUE;
187}
Note: See TracBrowser for help on using the repository browser.