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