1
2 /***************************************************************************/
3
4 /*
5 * Portions Copyright (c) 1999 GMRS Software GmbH
6 * Carl-von-Linde-Str. 38, D-85716 Unterschleissheim, http://www.gmrs.de
7 * All rights reserved.
8 *
9 * Author: Arno Unkrig <arno@unkrig.de>
10 */
11
12 /* This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License in the file COPYING for more details.
21 */
22
23 /***************************************************************************/
24
25 /*
26 * Changes to version 1.2.2 were made by Martin Bayer <mbayer@zedat.fu-berlin.de>
27 * Dates and reasons of modifications:
28 * Wed Jul 2 21:56:45 CEST 2003: ported to g++ 3.3
29 */
30
31 /***************************************************************************/
32
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <iostream>
37
38 #include "Area.h"
39 #include "string.h"
40
41 #define LATIN1_nbsp 160
42
43 /* ------------------------------------------------------------------------- */
44
45 #define malloc_array(type, size)\
46 ((type *) malloc(sizeof(type) * (size)))
47 #define realloc_array(array, type, size) \
48 ((array) = (type *) realloc((array), sizeof(type) * (size)))
49 #define copy_array(from, to, type, count) \
50 ((void) memcpy((to), (from), (count) * sizeof(type)))
51
52 /* ------------------------------------------------------------------------- */
53
Line(size_type l)54 Line::Line(size_type l) : length_(l), cells_(malloc_array(Cell, l))
55 {
56 Cell *p, *end = cells_ + l;
57 for (p = cells_; p != end; p++) p->clear();
58 }
59
Line(const char * p)60 Line::Line(const char *p) :
61 length_(strlen(p)),
62 cells_(malloc_array(Cell, length_))
63 {
64 Cell *q = cells_, *end = q + length_;
65 while (q != end) { q->character = *p++; q->attribute = Cell::NONE; q++; }
66 }
67
Line(const string & s)68 Line::Line(const string &s) :
69 length_(s.length()),
70 cells_(malloc_array(Cell, length_))
71 {
72 const char *p = s.c_str();
73 Cell *q = cells_, *end = q + length_;
74 while (q != end) { q->character = *p++; q->attribute = Cell::NONE; q++; }
75 }
76
~Line()77 Line::~Line()
78 {
79 free(cells_);
80 }
81
82 /* ------------------------------------------------------------------------- */
83
84 void
resize(size_type l)85 Line::resize(size_type l)
86 {
87 if (l == length()) return;
88 realloc_array(cells_, Cell, l);
89 for (size_type x = length(); x < l; x++) cells_[x].clear();
90 length_ = l;
91 }
92
93 void
insert(const Line & l,size_type x)94 Line::insert(const Line &l, size_type x)
95 {
96 enlarge(x + l.length());
97 const Cell *p = l.cells_, *end = p + l.length();
98 Cell *q = cells_ + x;
99 while (p != end) *q++ = *p++;
100 }
101
102 void
insert(const char * p,size_type x)103 Line::insert(const char *p, size_type x)
104 {
105 enlarge(x + strlen(p));
106 Cell *q = cells_ + x;
107 while (*p) q++->character = *p++;
108 }
109
110 void
insert(const string & s,size_type x)111 Line::insert(const string &s, size_type x)
112 {
113 insert(s.c_str(), x);
114 }
115
116 void
append(char c)117 Line::append(char c)
118 {
119 size_type x = length_;
120 resize(x + 1);
121 cells_[x].character = c;
122 cells_[x].attribute = Cell::NONE;
123 }
124
125 void
append(const Line & l)126 Line::append(const Line &l)
127 {
128 size_type x = length_;
129 enlarge(x + l.length_);
130 const Cell *p = l.cells_, *end = p + l.length();
131 Cell *q = cells_ + x;
132 while (p != end) *q++ = *p++;
133 }
134
135 void
append(const char * p)136 Line::append(const char *p)
137 {
138 size_type x = length_;
139 enlarge(x + strlen(p));
140 Cell *q = cells_ + x;
141 for (; *p; ++p, ++q) { q->character = *p; q->attribute = Cell::NONE; }
142 }
143
144 void
add_attribute(char addition)145 Line::add_attribute(char addition)
146 {
147 Cell *p = cells_, *end = cells_ + length_;
148
149 while(p != end) p++->attribute |= addition;
150 }
151
152 /* ------------------------------------------------------------------------- */
153
154 bool Area::use_backspaces = true;
155
156 /* ------------------------------------------------------------------------- */
157
Area()158 Area::Area() :
159 width_(0),
160 height_(0),
161 cells_(malloc_array(Cell *, 0))
162 {
163 }
164
Area(size_type w,size_type h,char c,char a)165 Area::Area(
166 size_type w /*= 0*/ ,
167 size_type h /*= 0*/ ,
168 char c /*= ' '*/ ,
169 char a /*= Cell::NONE*/
170 ) :
171 width_(w),
172 height_(h),
173 cells_(malloc_array(Cell *, h))
174 {
175 for (size_type y = 0; y < h; y++) {
176 Cell *p = cells_[y] = malloc_array(Cell, w), *end = p + w;
177 while (p != end) { p->character = c; p->attribute = a; p++; }
178 }
179 }
180
Area(const char * p)181 Area::Area(const char *p) :
182 width_(strlen(p)),
183 height_(1),
184 cells_(malloc_array(Cell *, 1))
185 {
186 cells_[0] = malloc_array(Cell, width_);
187 Cell *q = cells_[0], *end = q + width_;
188 while (q != end) { q->character = *p++; q->attribute = Cell::NONE; q++; }
189 }
190
Area(const string & s)191 Area::Area(const string &s) :
192 width_(s.length()),
193 height_(1),
194 cells_(malloc_array(Cell *, 1))
195 {
196 cells_[0] = malloc_array(Cell, width_);
197 Cell *q = cells_[0];
198 for (string::size_type i = 0; i < s.length(); ++i) {
199 q->character = s[i];
200 q->attribute = Cell::NONE;
201 q++;
202 }
203 }
204
Area(const Line & l)205 Area::Area(const Line &l) :
206 width_(l.length_),
207 height_(1),
208 cells_(malloc_array(Cell *, 1))
209 {
210 cells_[0] = malloc_array(Cell, width_);
211 copy_array(l.cells_, cells_[0], Cell, width_);
212 }
213
~Area()214 Area::~Area()
215 {
216 for (size_type y = 0; y < height(); y++) free(cells_[y]);
217 free(cells_);
218 }
219
220 /* ------------------------------------------------------------------------- */
221
222 const Area &
223 Area::operator>>=(size_type rs)
224 {
225 if (rs > 0) {
226 resize(width_ + rs, height_);
227 for (size_type y = 0; y < height_; y++) {
228 Cell *c = cells_[y];
229 memmove(c + rs, c, (width_ - rs) * sizeof(Cell));
230 for (size_type x = 0; x < rs; x++) {
231 c[x].character = ' ';
232 c[x].attribute = Cell::NONE;
233 }
234 }
235 }
236 return *this;
237 }
238
239 void
resize(size_type w,size_type h)240 Area::resize(size_type w, size_type h)
241 {
242 size_type y_max = h < height() ? h : height();
243
244 if (w > width()) {
245 for (size_type y = 0; y < y_max; y++) {
246 realloc_array(cells_[y], Cell, w);
247 Cell *p = cells_[y] + width(), *end = cells_[y] + w;
248 while (p != end) p++->clear();
249 }
250 } else
251 if (w < width()) {
252 for (size_type y = 0; y < y_max; y++) {
253 realloc_array(cells_[y], Cell, w);
254 }
255 }
256
257 if (h > height()) {
258 realloc_array(cells_, Cell *, h);
259 for (size_type y = height(); y < h; y++) {
260 Cell *p = cells_[y] = malloc_array(Cell, w), *end = p + w;
261 while (p != end) p++->clear();
262 }
263 } else
264 if (h < height()) {
265 for (size_type y = h; y < height(); y++) free(cells_[y]);
266 realloc_array(cells_, Cell *, h);
267 }
268
269 width_ = w;
270 height_ = h;
271 }
272
273 void
enlarge(size_type w,size_type h)274 Area::enlarge(size_type w, size_type h)
275 {
276 if (w > width() || h > height()) {
277 resize(w > width() ? w : width(), h > height() ? h : height());
278 }
279 }
280
281 void
insert(const Area & a,size_type x,size_type y)282 Area::insert(const Area &a, size_type x, size_type y)
283 {
284 enlarge(x + a.width(), y + a.height());
285
286 for (size_type i = 0; i < a.height(); i++) {
287 const Cell *p = a.cells_[i], *end = p + a.width();
288 Cell *q = cells_[y + i] + x;
289 while (p != end) *q++ = *p++;
290 }
291 }
292
293 void
insert(const Area & a,size_type x,size_type y,size_type w,size_type h,int halign,int valign)294 Area::insert(
295 const Area &a,
296 size_type x,
297 size_type y,
298 size_type w,
299 size_type h,
300 int halign,
301 int valign
302 )
303 {
304 if (halign != LEFT && a.width() < w) x += (
305 halign == CENTER ? (w - a.width()) / 2 :
306 halign == RIGHT ? w - a.width() :
307 0
308 );
309 if (valign != TOP && a.height() < h) y += (
310 valign == MIDDLE ? (h - a.height()) / 2 :
311 valign == BOTTOM ? h - a.height() :
312 0
313 );
314 insert(a, x, y);
315 }
316
317 void
insert(const Cell & c,size_type x,size_type y)318 Area::insert(const Cell &c, size_type x, size_type y)
319 {
320 enlarge(x + 1, y + 1);
321 cells_[y][x] = c;
322 }
323
324 void
fill(const Cell & c,size_type x,size_type y,size_type w,size_type h)325 Area::fill(const Cell &c, size_type x, size_type y, size_type w, size_type h)
326 {
327 enlarge(x + w, y + h);
328 for (size_type yy = y; yy < y + h; yy++) {
329 Cell *p = &cells_[yy][x];
330 for (size_type i = 0; i < w; i++) *p++ = c;
331 }
332 }
333
334 void
insert(const Cell * p,size_type count,size_type x,size_type y)335 Area::insert(const Cell *p, size_type count, size_type x, size_type y)
336 {
337 enlarge(x + count, y + 1);
338 Cell *q = &cells_[y][x];
339 while (count--) *q++ = *p++;
340 }
341
342 void
insert(char c,size_type x,size_type y)343 Area::insert(char c, size_type x, size_type y)
344 {
345 enlarge(x + 1, y + 1);
346 cells_[y][x].character = c;
347 }
348
349 void
insert(const string & s,size_type x,size_type y)350 Area::insert(const string &s, size_type x, size_type y)
351 {
352 enlarge(x + s.length(), y + 1);
353 Cell *cell = &cells_[y][x];
354 for (string::size_type i = 0; i < s.length(); i++) {
355 cell->character = s[i];
356 cell->attribute = Cell::NONE;
357 cell++;
358 }
359 }
360
361 void
prepend(int n)362 Area::prepend(int n)
363 {
364 if (n <= 0) return;
365
366 realloc_array(cells_, Cell *, height() + n);
367 memmove(cells_ + n, cells_, height() * sizeof(*cells_));
368 for (int y = 0; y < n; ++y) {
369 Cell *p = cells_[y] = malloc_array(Cell, width()), *end = p + width();
370 while (p != end) p++->clear();
371 }
372 height_ += n;
373 }
374
375 const Area &
376 Area::operator+=(const Area &x)
377 {
378 insert(x, 0, height());
379 return *this;
380 }
381
382 void
fill(char c,size_type x,size_type y,size_type w,size_type h)383 Area::fill(char c, size_type x, size_type y, size_type w, size_type h)
384 {
385 enlarge(x + w, y + h);
386 for (size_type yy = y; yy < y + h; yy++) {
387 Cell *p = &cells_[yy][x];
388 for (size_type i = 0; i < w; i++) p++->character = c;
389 }
390 }
391
392 void
add_attribute(char addition)393 Area::add_attribute(char addition)
394 {
395 for (size_type y = 0; y < height(); y++) {
396 Cell *p = cells_[y], *end = p + width();
397 while (p != end && p->character == ' ') ++p;
398 Cell *q = p;
399 while (p != end) {
400 if (p++->character != ' ') {
401 while (q < p) q++->attribute |= addition;
402 }
403 }
404 }
405 }
406
407 void
add_attribute(char addition,size_type x,size_type y,size_type w,size_type h)408 Area::add_attribute(
409 char addition,
410 size_type x,
411 size_type y,
412 size_type w,
413 size_type h
414 )
415 {
416 enlarge(x + w, y + h);
417 for (size_type yy = y; yy < y + h; yy++) {
418 Cell *p = &cells_[yy][x], *end = p + w;
419 while (p != end) p++->attribute |= addition;
420 }
421 }
422
423 /* ------------------------------------------------------------------------- */
424
backspace(ostream & os)425 ostream &backspace(ostream &os) { return os << '\b'; }
426
427 ostream &
428 operator<<(ostream &os, const Area &a)
429 {
430 for (Area::size_type y = 0; y < a.height(); y++) {
431 const Cell *cell = a.cells_[y], *end = cell + a.width();
432 while (
433 end != cell &&
434 end[-1].character == ' ' &&
435 (end[-1].attribute & (Cell::UNDERLINE | Cell::STRIKETHROUGH)) == 0
436 ) end--;
437
438 for (const Cell *p = cell; p != end; p++) {
439 char c = p->character;
440 char a = p->attribute;
441
442 if (c == (char) LATIN1_nbsp) c = ' ';
443
444 if (a == Cell::NONE) {
445 os << c;
446 } else {
447 if (Area::use_backspaces) {
448
449 /*
450 * No LESS / terminal combination that I know of supports
451 * dash-backspace-character as "strikethrough". Pity.
452 */
453 if (a & Cell::STRIKETHROUGH) os << '-' << backspace;
454
455 /*
456 * No LESS that I know of can combine underlining and boldface. In
457 * practice, boldface always takes precedence.
458 *
459 * It's not a good idea to optimize an underlined space as a single
460 * underscore (as opposed to underscore-backspace-space) -- this
461 * would not look nice next to an underlined character.
462 */
463 if ((a & Cell::UNDERLINE) ) os << '_' << backspace;
464 if ((a & Cell::BOLD ) && c != ' ') os << c << backspace;
465 os << c;
466 } else {
467 os << (c == ' ' && (a & Cell::UNDERLINE) ? '_' : c);
468 }
469 }
470 }
471 os << std::endl;
472 }
473
474 return os;
475 }
476
477 /* ------------------------------------------------------------------------- */
478
479