source: branches/nanovis2/packages/vizservers/vtkvis/ReadBuffer.cpp @ 3305

Last change on this file since 3305 was 3305, checked in by ldelgass, 11 years ago

sync with trunk

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