source: geovis/trunk/ReadBuffer.cpp @ 4829

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

Add prelimilary skeleton for geovis map rendering server. Not functional, not
integrated into configure, etc.

File size: 5.0 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2013  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 GeoVis;
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.