1 /* $Id: grid.c,v 1.15 2009-03-30 19:44:55 nicm Exp $ */
4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
26 * Grid data. This is the basic data structure that represents what is shown on
29 * A grid is a grid of cells (struct grid_cell). Lines are not allocated until
30 * cells in that line are written to. The grid is split into history and
31 * viewable data with the history starting at row (line) 0 and extending to
32 * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All
33 * functions in this file work on absolute coordinates, grid-view.c has
34 * functions which work on the screen data.
37 /* Default grid cell data. */
38 const struct grid_cell grid_default_cell
= { 0, 0, 8, 8, ' ' };
40 #define grid_put_cell(gd, px, py, gc) do { \
41 memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \
43 #define grid_put_utf8(gd, px, py, gc) do { \
44 memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \
47 int grid_check_x(struct grid
*, u_int
);
48 int grid_check_y(struct grid
*, u_int
);
52 grid_check_x(struct grid
*gd
, u_int px
)
55 log_fatalx("x out of range: %u", px
);
60 grid_check_y(struct grid
*gd
, u_int py
)
62 if ((py
) >= (gd
)->hsize
+ (gd
)->sy
)
63 log_fatalx("y out of range: %u", py
);
68 grid_check_x(struct grid
*gd
, u_int px
)
70 if ((px
) >= (gd
)->sx
) {
71 log_debug("x out of range: %u", px
);
78 grid_check_y(struct grid
*gd
, u_int py
)
80 if ((py
) >= (gd
)->hsize
+ (gd
)->sy
) {
81 log_debug("y out of range: %u", py
);
88 /* Create a new grid. */
90 grid_create(u_int sx
, u_int sy
, u_int hlimit
)
94 gd
= xmalloc(sizeof *gd
);
101 gd
->size
= xcalloc(gd
->sy
, sizeof *gd
->size
);
102 gd
->data
= xcalloc(gd
->sy
, sizeof *gd
->data
);
104 gd
->usize
= xcalloc(gd
->sy
, sizeof *gd
->usize
);
105 gd
->udata
= xcalloc(gd
->sy
, sizeof *gd
->udata
);
112 grid_destroy(struct grid
*gd
)
116 for (yy
= 0; yy
< gd
->hsize
+ gd
->sy
; yy
++) {
117 if (gd
->udata
[yy
] != NULL
)
118 xfree(gd
->udata
[yy
]);
119 if (gd
->data
[yy
] != NULL
)
123 if (gd
->udata
!= NULL
)
125 if (gd
->usize
!= NULL
)
128 if (gd
->data
!= NULL
)
130 if (gd
->size
!= NULL
)
138 grid_compare(struct grid
*ga
, struct grid
*gb
)
140 struct grid_cell
*gca
, *gcb
;
141 struct grid_utf8
*gua
, *gub
;
144 if (ga
->sx
!= gb
->sx
|| ga
->sy
!= ga
->sy
)
147 for (yy
= 0; yy
< ga
->sy
; yy
++) {
148 if (ga
->size
[yy
] != gb
->size
[yy
])
150 for (xx
= 0; xx
< ga
->sx
; xx
++) {
151 gca
= &ga
->data
[yy
][xx
];
152 gcb
= &gb
->data
[yy
][xx
];
153 if (memcmp(gca
, gcb
, sizeof (struct grid_cell
)) != 0)
155 if (!(gca
->flags
& GRID_FLAG_UTF8
))
157 gua
= &ga
->udata
[yy
][xx
];
158 gub
= &gb
->udata
[yy
][xx
];
159 if (memcmp(gua
, gub
, sizeof (struct grid_utf8
)) != 0)
167 /* Scroll a line into the history. */
169 grid_scroll_line(struct grid
*gd
)
175 if (gd
->hsize
>= gd
->hlimit
- 1) {
176 /* If the limit is hit, free the bottom 10% and shift up. */
177 yy
= gd
->hlimit
/ 10;
181 grid_move_lines(gd
, 0, yy
, gd
->hsize
+ gd
->sy
- yy
);
185 yy
= gd
->hsize
+ gd
->sy
;
187 gd
->size
= xrealloc(gd
->size
, yy
+ 1, sizeof *gd
->size
);
189 gd
->data
= xrealloc(gd
->data
, yy
+ 1, sizeof *gd
->data
);
192 gd
->usize
= xrealloc(gd
->usize
, yy
+ 1, sizeof *gd
->usize
);
194 gd
->udata
= xrealloc(gd
->udata
, yy
+ 1, sizeof *gd
->udata
);
195 gd
->udata
[yy
] = NULL
;
200 /* Reduce line to fit to cell. */
202 grid_reduce_line(struct grid
*gd
, u_int py
, u_int sx
)
204 if (sx
< gd
->size
[py
]) {
205 gd
->data
[py
] = xrealloc(gd
->data
[py
], sx
, sizeof **gd
->data
);
208 if (sx
< gd
->usize
[py
]) {
209 gd
->udata
[py
] = xrealloc(gd
->udata
[py
], sx
, sizeof **gd
->udata
);
214 /* Expand line to fit to cell. */
216 grid_expand_line(struct grid
*gd
, u_int py
, u_int sx
)
220 if (sx
<= gd
->size
[py
])
223 gd
->data
[py
] = xrealloc(gd
->data
[py
], sx
, sizeof **gd
->data
);
224 for (xx
= gd
->size
[py
]; xx
< sx
; xx
++)
225 grid_put_cell(gd
, xx
, py
, &grid_default_cell
);
229 /* Expand line to fit to cell for UTF-8. */
231 grid_expand_line_utf8(struct grid
*gd
, u_int py
, u_int sx
)
233 if (sx
<= gd
->usize
[py
])
236 gd
->udata
[py
] = xrealloc(gd
->udata
[py
], sx
, sizeof **gd
->udata
);
240 /* Get cell for reading. */
241 const struct grid_cell
*
242 grid_peek_cell(struct grid
*gd
, u_int px
, u_int py
)
244 if (grid_check_x(gd
, px
) != 0)
245 return (&grid_default_cell
);
246 if (grid_check_y(gd
, py
) != 0)
247 return (&grid_default_cell
);
249 if (px
>= gd
->size
[py
])
250 return (&grid_default_cell
);
251 return (&gd
->data
[py
][px
]);
254 /* Get cell at relative position (for writing). */
256 grid_get_cell(struct grid
*gd
, u_int px
, u_int py
)
258 if (grid_check_x(gd
, px
) != 0)
260 if (grid_check_y(gd
, py
) != 0)
263 grid_expand_line(gd
, py
, px
+ 1);
264 return (&gd
->data
[py
][px
]);
267 /* Set cell at relative position. */
270 struct grid
*gd
, u_int px
, u_int py
, const struct grid_cell
*gc
)
272 if (grid_check_x(gd
, px
) != 0)
274 if (grid_check_y(gd
, py
) != 0)
277 grid_expand_line(gd
, py
, px
+ 1);
278 grid_put_cell(gd
, px
, py
, gc
);
281 /* Get UTF-8 for reading. */
282 const struct grid_utf8
*
283 grid_peek_utf8(struct grid
*gd
, u_int px
, u_int py
)
285 if (grid_check_x(gd
, px
) != 0)
287 if (grid_check_y(gd
, py
) != 0)
290 if (px
>= gd
->usize
[py
])
292 return (&gd
->udata
[py
][px
]);
295 /* Get utf8 at relative position (for writing). */
297 grid_get_utf8(struct grid
*gd
, u_int px
, u_int py
)
299 if (grid_check_x(gd
, px
) != 0)
301 if (grid_check_y(gd
, py
) != 0)
304 grid_expand_line_utf8(gd
, py
, px
+ 1);
305 return (&gd
->udata
[py
][px
]);
308 /* Set utf8 at relative position. */
311 struct grid
*gd
, u_int px
, u_int py
, const struct grid_utf8
*gc
)
313 if (grid_check_x(gd
, px
) != 0)
315 if (grid_check_y(gd
, py
) != 0)
318 grid_expand_line_utf8(gd
, py
, px
+ 1);
319 grid_put_utf8(gd
, px
, py
, gc
);
323 * Clear area. Note this is different from a fill as it just omits unallocated
327 grid_clear(struct grid
*gd
, u_int px
, u_int py
, u_int nx
, u_int ny
)
331 GRID_DEBUG(gd
, "px=%u, py=%u, nx=%u, ny=%u", px
, py
, nx
, ny
);
333 if (nx
== 0 || ny
== 0)
336 if (px
== 0 && nx
== gd
->sx
) {
337 grid_clear_lines(gd
, py
, ny
);
341 if (grid_check_x(gd
, px
) != 0)
343 if (grid_check_x(gd
, px
+ nx
- 1) != 0)
345 if (grid_check_y(gd
, py
) != 0)
347 if (grid_check_y(gd
, py
+ ny
- 1) != 0)
350 for (yy
= py
; yy
< py
+ ny
; yy
++) {
351 for (xx
= px
; xx
< px
+ nx
; xx
++) {
352 if (xx
>= gd
->size
[yy
])
354 grid_put_cell(gd
, xx
, yy
, &grid_default_cell
);
359 /* Clear lines. This just frees and truncates the lines. */
361 grid_clear_lines(struct grid
*gd
, u_int py
, u_int ny
)
365 GRID_DEBUG(gd
, "py=%u, ny=%u", py
, ny
);
370 if (grid_check_y(gd
, py
) != 0)
372 if (grid_check_y(gd
, py
+ ny
- 1) != 0)
375 for (yy
= py
; yy
< py
+ ny
; yy
++) {
376 if (gd
->data
[yy
] != NULL
) {
381 if (gd
->udata
[yy
] != NULL
) {
382 xfree(gd
->udata
[yy
]);
383 gd
->udata
[yy
] = NULL
;
389 /* Move a group of lines. */
391 grid_move_lines(struct grid
*gd
, u_int dy
, u_int py
, u_int ny
)
395 GRID_DEBUG(gd
, "dy=%u, py=%u, ny=%u", dy
, py
, ny
);
397 if (ny
== 0 || py
== dy
)
400 if (grid_check_y(gd
, py
) != 0)
402 if (grid_check_y(gd
, py
+ ny
- 1) != 0)
404 if (grid_check_y(gd
, dy
) != 0)
406 if (grid_check_y(gd
, dy
+ ny
- 1) != 0)
409 /* Free any lines which are being replaced. */
410 for (yy
= dy
; yy
< dy
+ ny
; yy
++) {
411 if (yy
>= py
&& yy
< py
+ ny
)
413 grid_clear_lines(gd
, yy
, 1);
416 memmove(&gd
->data
[dy
], &gd
->data
[py
], ny
* (sizeof *gd
->data
));
417 memmove(&gd
->size
[dy
], &gd
->size
[py
], ny
* (sizeof *gd
->size
));
419 memmove(&gd
->udata
[dy
], &gd
->udata
[py
], ny
* (sizeof *gd
->udata
));
420 memmove(&gd
->usize
[dy
], &gd
->usize
[py
], ny
* (sizeof *gd
->usize
));
422 /* Wipe any lines that have been moved (without freeing them). */
423 for (yy
= py
; yy
< py
+ ny
; yy
++) {
424 if (yy
>= dy
&& yy
< dy
+ ny
)
428 gd
->udata
[yy
] = NULL
;
433 /* Clear a group of cells. */
435 grid_clear_cells(struct grid
*gd
, u_int px
, u_int py
, u_int nx
)
439 GRID_DEBUG(gd
, "px=%u, py=%u, nx=%u", px
, py
, nx
);
444 if (grid_check_x(gd
, px
) != 0)
446 if (grid_check_x(gd
, px
+ nx
- 1) != 0)
448 if (grid_check_y(gd
, py
) != 0)
451 for (xx
= px
; xx
< px
+ nx
; xx
++) {
452 if (xx
>= gd
->size
[py
])
454 grid_put_cell(gd
, xx
, py
, &grid_default_cell
);
458 /* Move a group of cells. */
460 grid_move_cells(struct grid
*gd
, u_int dx
, u_int px
, u_int py
, u_int nx
)
464 GRID_DEBUG(gd
, "dx=%u, px=%u, py=%u, nx=%u", dx
, px
, py
, nx
);
466 if (nx
== 0 || px
== dx
)
469 if (grid_check_x(gd
, px
) != 0)
471 if (grid_check_x(gd
, px
+ nx
- 1) != 0)
473 if (grid_check_x(gd
, dx
+ nx
- 1) != 0)
475 if (grid_check_y(gd
, py
) != 0)
478 grid_expand_line(gd
, py
, px
+ nx
);
479 grid_expand_line(gd
, py
, dx
+ nx
);
480 memmove(&gd
->data
[py
][dx
], &gd
->data
[py
][px
], nx
* (sizeof **gd
->data
));
482 if (gd
->udata
[py
] != NULL
) {
483 grid_expand_line_utf8(gd
, py
, px
+ nx
);
484 grid_expand_line_utf8(gd
, py
, dx
+ nx
);
485 memmove(&gd
->udata
[py
][dx
],
486 &gd
->udata
[py
][px
], nx
* (sizeof **gd
->udata
));
489 /* Wipe any cells that have been moved. */
490 for (xx
= px
; xx
< px
+ nx
; xx
++) {
491 if (xx
>= dx
&& xx
< dx
+ nx
)
493 grid_put_cell(gd
, xx
, py
, &grid_default_cell
);