1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 // CharInBuffer.h
4 //------------------------------------------------------------------------------
5 // Copyright (C) 2002,2005 Vladislav Grinchenko
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //------------------------------------------------------------------------------
12 #ifndef CHAR_IN_BUFFER_H
13 #define CHAR_IN_BUFFER_H
14
15 /** @file CharInBuffer.h
16
17 A bucket for collecting character-based stream records of certain
18 length or terminated by designated character(s).
19 */
20
21 #include <sys/types.h>
22
23 #include "assa/Assure.h"
24 #include "assa/Socket.h"
25
26 #include <string>
27 using std::string;
28
29 namespace ASSA {
30
31 /**
32 * CharInBuffer is a bucket for the character-based streams/messages.
33 * It helps in reading, parsing, and storing record-oriented character
34 * streams from Socket stream asynchronously. The record terminator can
35 * be multibyte. The terminator is detected and removed from the bucket.
36 * When terminator is detected, the block of characters collected in the bucket
37 * is ready to be processed further by the application according to its
38 * communication protocol.
39 * If either Socket read() error is encountered, or an overflow occurs
40 * (number of characters read exceeds the maximum limit), the object goes into
41 * the error state and won't accept further input, unless reset.
42 */
43
44 class CharInBuffer
45 {
46 public:
47 /** Constructor
48 * @param size_ Maximum expected size before buffer overflow
49 * @param delimiter_ End-of-record character(s). Can be multi-byte.
50 */
51 CharInBuffer (size_t size_, const string& delimiter_);
52
53 /** Read bytes from Socket stream until either record delimiter is
54 * detected, or EOF occured, or Socket stream is exhausted.
55 * @return Socket reference
56 */
57 friend ASSA::Socket& operator>>(ASSA::Socket&, ASSA::CharInBuffer&);
58
59 /** Test the state of an object
60 * @return true if the object holds a complete message;
61 * false otherwise (eof, buffer overflow, or incomplete)
62 */
63 operator void* () const;
64
65 /// Get the constant character pointer to the buffer
c_str()66 const char* c_str () const { return m_buffer.c_str (); }
67
68 /// Bytes in the buffer so far
length()69 size_t length () const { return m_buffer.length (); }
70
71 /// Bytes in the buffer so far
size()72 size_t size () const { return m_buffer.size (); }
73
74 /** Discard all accumulated characters and be ready to receive
75 * a new message.
76 */
77 void reset ();
78
79 /// Write the state of an object to the log file.
80 void dump () const;
81
82 /** @enum state_t
83 * States: start, waiting, complete, error
84 */
85 enum state_t {
86 start, /**< start state */
87 waiting, /**< incomplete record is in the buffer */
88 complete, /**< matched end-of-record - full record */
89 error /**< overflow or Socket I/O error */
90 };
91
92 /// Report the current state of the object
state()93 state_t state () const { return m_state; }
94
95 private:
96 /// Report the state name
97 static const char* state_name (state_t state_);
98
99 /// Go to the new state
state(state_t new_state_)100 void state (state_t new_state_) { m_state = new_state_; }
101
102 /// Remove the delimiter from the end of the buffer
103 void chop ();
104
105 private:
106 /// Internal state of an object
107 state_t m_state;
108
109 /// Buffer to store the bytes received
110 std::string m_buffer;
111
112 /// Maximum allowable size (delimiter included) before overflow occurs
113 size_t m_max_size;
114
115 /// Delimiter. Multibyte delimiter is allowed.
116 std::string m_delimiter;
117 };
118
119 } // end namespace ASSA
120
121 /*******************************************************************************
122 Inline member functions
123 *******************************************************************************/
124 using namespace ASSA;
125
126 inline
127 CharInBuffer::
128 operator void* () const
129 {
130 return (m_state == complete
131 ? (void *) (-1) // good state
132 : (void *) 0); // bad state
133 }
134
135 inline void
136 CharInBuffer::
reset()137 reset ()
138 {
139 m_buffer = "";
140 state (waiting);
141 }
142
143 inline void
144 CharInBuffer::
chop()145 chop ()
146 {
147 m_buffer.replace (m_buffer.find (m_delimiter), m_delimiter.length (), "");
148 }
149
150 #endif /* CHAR_IN_BUFFER_H */
151