summaryrefslogtreecommitdiff
path: root/src/strbuffer.h
blob: f932964c084992175b05c4b8b545f9a25cb4eef5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/***************************************************************************
 *   Copyright (C) 2008-2012 by Andrzej Rybczak                            *
 *   electricityispower@gmail.com                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
 ***************************************************************************/

#ifndef _STRBUFFER_H
#define _STRBUFFER_H

#include "tolower.h"
#include "window.h"

#include <sstream>
#include <list>

namespace NCurses
{
	/// Buffer template class that can store text along with its
	/// format attributes. The content can be easily printed to
	/// window or taken as raw string at any time.
	///
	template <typename C> class basic_buffer
	{
		/// Struct used for storing information about
		/// one color/format flag along with its position
		///
		struct FormatPos
		{
			size_t Position;
			short Value;
			
			bool operator<(const FormatPos &f)
			{
				return Position < f.Position;
			}
			
			bool operator==(const FormatPos &f)
			{
				return Position == f.Position && Value == f.Value;
			}
		};
		
		/// Internal buffer for storing raw text
		///
		std::basic_ostringstream<C> itsString;
		
		/// List used for storing formatting informations
		///
		std::list<FormatPos> itsFormat;
		
		/// Pointer to temporary string
		/// @see SetTemp()
		///
		std::basic_string<C> *itsTempString;
		
		public:
			/// Constructs an empty buffer
			///
			basic_buffer() : itsTempString(0) { }
			
			/// Constructs a buffer from the existed one
			/// @param b copied buffer
			///
			basic_buffer(const basic_buffer &b);
			
			/// @return raw content of the buffer without formatting informations
			///
			std::basic_string<C> Str() const;
			
			/// Searches for given string in buffer and sets format/color at the
			/// beginning and end of it using val_b and val_e flags accordingly
			/// @param val_b flag set at the beginning of found occurence of string
			/// @param s string that function seaches for
			/// @param val_e flag set at the end of found occurence of string
			/// @param case_sensitive indicates whether algorithm should care about case sensitivity
			/// @param for_each indicates whether function searches through whole buffer and sets
			/// the format for all occurences of given string or stops after the first one
			/// @return true if at least one occurence of the string was found, false otherwise
			///
			bool SetFormatting(short val_b, std::basic_string<C> s, short val_e,
					   bool case_sensitive, bool for_each = 1);
			
			/// Searches for given string in buffer and removes given
			/// format/color from the beginning and end of its occurence
			/// @param val_b flag to be removed from the beginning of the string
			/// @param s string that function seaches for
			/// @param val_e flag to be removed from the end of the string
			/// @param case_sensitive indicates whether algorithm should care about case sensitivity
			/// @param for_each indicates whether function searches through whole buffer and removes
			/// given format from all occurences of given string or stops after the first one
			///
			void RemoveFormatting(short val_b, std::basic_string<C> pattern, short val_e,
					      bool case_sensitive, bool for_each = 1);
			
			/// Removes all formating applied to string in buffer.
			///
			void RemoveFormatting();
			
			/// Sets the pointer to string, that will be passed in operator<<() to window
			/// object instead of the internal buffer. This is useful if you took the content
			/// of the buffer, modified it somehow and want to print the modified version instead
			/// of the original one, but with the original formatting informations. Note that after
			/// you're done with the printing etc., this pointer has to be set to null.
			/// @param tmp address of the temporary string
			///
			void SetTemp(std::basic_string<C> *tmp);
			
			/// Prints to window object given part of the string, loading all needed formatting info
			/// and cleaning up after. The main goal of this function is to provide interface for
			/// colorful scrollers.
			/// @param w window object that we want to print to
			/// @param start_pos reference to start position of the string. note that this variable is
			/// incremented by one after each call or set to 0 if end of string is reached
			/// @param width width of the string to be printed
			/// @param separator additional text to be placed between the end and the beginning of
			/// the string
			///
			void Write(Window &w, size_t &start_pos, size_t width,
				   const std::basic_string<C> &separator) const;
			
			/// Clears the content of the buffer and its formatting informations
			///
			void Clear();
			
			/// @param t any object that has defined ostream &operator<<()
			/// @return reference to itself
			///
			template <typename T> basic_buffer<C> &operator<<(const T &t)
			{
				itsString << t;
				return *this;
			}
			
			/// Handles colors
			/// @return reference to itself
			///
			basic_buffer<C> &operator<<(Color color);
			
			/// Handles format flags
			/// @return reference to itself
			///
			basic_buffer<C> &operator<<(Format f);
			
			/// Handles copying one buffer to another using operator<<()
			/// @param buf buffer to be copied
			/// @return reference to itself
			///
			basic_buffer<C> &operator<<(const basic_buffer<C> &buf);
			
			/// Friend operator, that handles printing
			/// the content of buffer to window object
			friend Window &operator<< <>(Window &, const basic_buffer<C> &);
			
		private:
			/// Loads an attribute to given window object
			/// @param w window object we want to load attribute to
			/// @param value value of attribute to be loaded
			///
			void LoadAttribute(Window &w, short value) const;
	};
	
	/// Standard buffer that uses narrow characters
	///
	typedef basic_buffer<char> Buffer;
	
	/// Standard buffer that uses wide characters
	///
	typedef basic_buffer<wchar_t> WBuffer;
}

template <typename C> NCurses::basic_buffer<C>::basic_buffer(const basic_buffer &b) : itsFormat(b.itsFormat),
										itsTempString(b.itsTempString)
{
	itsString << b.itsString.str();
}

template <typename C> std::basic_string<C> NCurses::basic_buffer<C>::Str() const
{
	return itsString.str();
}

template <typename C> bool NCurses::basic_buffer<C>::SetFormatting(	short val_b,
									std::basic_string<C> s,
									short val_e,
									bool case_sensitive,
									bool for_each
								  )
{
	if (s.empty())
		return false;
	bool result = false;
	std::basic_string<C> base = itsString.str();
	if (!case_sensitive)
	{
		ToLower(s);
		ToLower(base);
	}
	FormatPos fp;
	for (size_t i = base.find(s); i != std::basic_string<C>::npos; i = base.find(s, i))
	{
		result = true;
		fp.Value = val_b;
		fp.Position = i;
		itsFormat.push_back(fp);
		i += s.length();
		fp.Value = val_e;
		fp.Position = i;
		itsFormat.push_back(fp);
		if (!for_each)
			break;
	}
	itsFormat.sort();
	return result;
}

template <typename C> void NCurses::basic_buffer<C>::RemoveFormatting(	short val_b,
									std::basic_string<C> pattern,
									short val_e,
									bool case_sensitive,
									bool for_each
								     )
{
	if (pattern.empty())
		return;
	std::basic_string<C> base = itsString.str();
	if (!case_sensitive)
	{
		ToLower(pattern);
		ToLower(base);
	}
	FormatPos fp;
	for (size_t i = base.find(pattern); i != std::basic_string<C>::npos; i = base.find(pattern, i))
	{
		fp.Value = val_b;
		fp.Position = i;
		itsFormat.remove(fp);
		i += pattern.length();
		fp.Value = val_e;
		fp.Position = i;
		itsFormat.remove(fp);
		if (!for_each)
			break;
	}
}

template <typename C> void NCurses::basic_buffer<C>::RemoveFormatting()
{
	itsFormat.clear();
}

template <typename C> void NCurses::basic_buffer<C>::SetTemp(std::basic_string<C> *tmp)
{
	itsTempString = tmp;
}

template <typename C> void NCurses::basic_buffer<C>::Write(	Window &w,
								size_t &start_pos,
								size_t width,
								const std::basic_string<C> &separator
							  ) const
{
	std::basic_string<C> s = itsString.str();
	size_t len = Window::Length(s);
	
	if (len > width)
	{
		s += separator;
		len = 0;
		
		typename std::list<typename NCurses::basic_buffer<C>::FormatPos>::const_iterator lb = itsFormat.begin();
		if (itsFormat.back().Position > start_pos) // if there is no attributes from current position, don't load them
		{
			// load all attributes that are before start position
			for (; lb->Position < start_pos; ++lb)
				LoadAttribute(w, lb->Value);
		}
		
		for (size_t i = start_pos; i < s.length() && len < width; ++i)
		{
			while (i == lb->Position && lb != itsFormat.end())
			{
				LoadAttribute(w, lb->Value);
				++lb;
			}
			if ((len += wcwidth(s[i])) > width)
				break;
			w << s[i];
		}
		if (++start_pos >= s.length())
			start_pos = 0;
		
		if (len < width)
			lb = itsFormat.begin();
		for (size_t i = 0; len < width; ++i)
		{
			while (i == lb->Position && lb != itsFormat.end())
			{
				LoadAttribute(w, lb->Value);
				++lb;
			}
			if ((len += wcwidth(s[i])) > width)
				break;
			w << s[i];
		}
		// load all remained attributes to clean up
		for (; lb != itsFormat.end(); ++lb)
			LoadAttribute(w, lb->Value);
	}
	else
		w << *this;
}

template <typename C> void NCurses::basic_buffer<C>::Clear()
{
	itsString.str(std::basic_string<C>());
	itsFormat.clear();
}

template <typename C> void NCurses::basic_buffer<C>::LoadAttribute(Window &w, short value) const
{
	if (value < NCurses::fmtNone)
		w << NCurses::Color(value);
	else
		w << NCurses::Format(value);
}

template <typename C> NCurses::basic_buffer<C> &NCurses::basic_buffer<C>::operator<<(Color color)
{
	FormatPos f;
	f.Position = itsString.str().length();
	f.Value = color;
	itsFormat.push_back(f);
	return *this;
}

template <typename C> NCurses::basic_buffer<C> &NCurses::basic_buffer<C>::operator<<(Format f)
{
	return operator<<(Color(f));
}

template <typename C> NCurses::basic_buffer<C> &NCurses::basic_buffer<C>::operator<<(const NCurses::basic_buffer<C> &buf)
{
	size_t len = itsString.str().length();
	itsString << buf.itsString.str();
	std::list<FormatPos> tmp = buf.itsFormat;
	if (len)
		for (typename std::list<typename NCurses::basic_buffer<C>::FormatPos>::iterator it = tmp.begin(); it != tmp.end(); ++it)
			it->Position += len;
	itsFormat.merge(tmp);
	return *this;
}

template <typename C> NCurses::Window &operator<<(NCurses::Window &w, const NCurses::basic_buffer<C> &buf)
{
	const std::basic_string<C> &s = buf.itsTempString ? *buf.itsTempString : buf.itsString.str();
	if (buf.itsFormat.empty())
	{
		w << s;
	}
	else
	{
		std::basic_string<C> tmp;
		typename std::list<typename NCurses::basic_buffer<C>::FormatPos>::const_iterator b = buf.itsFormat.begin();
		typename std::list<typename NCurses::basic_buffer<C>::FormatPos>::const_iterator e = buf.itsFormat.end();
		for (size_t i = 0; i < s.length() || b != e; ++i)
		{
			while (b != e && i == b->Position)
			{
				if (!tmp.empty())
				{
					w << tmp;
					tmp.clear();
				}
				buf.LoadAttribute(w, b->Value);
				b++;
			}
			if (i < s.length())
				tmp += s[i];
		}
		if (!tmp.empty())
			w << tmp;
	}
	return w;
}

#endif