[BACK]Return to grid.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/grid.c, Revision 1.7

1.7     ! nicm        1: /* $OpenBSD: grid.c,v 1.6 2009/07/11 20:11:18 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
                      5:  *
                      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.
                      9:  *
                     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.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <string.h>
                     22:
                     23: #include "tmux.h"
                     24:
                     25: /*
                     26:  * Grid data. This is the basic data structure that represents what is shown on
                     27:  * screen.
                     28:  *
                     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.
                     35:  */
                     36:
                     37: /* Default grid cell data. */
                     38: const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
                     39:
                     40: #define grid_put_cell(gd, px, py, gc) do {                     \
                     41:        memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \
                     42: } while (0)
                     43: #define grid_put_utf8(gd, px, py, gc) do {                     \
                     44:        memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \
                     45: } while (0)
                     46:
                     47: int    grid_check_x(struct grid *, u_int);
                     48: int    grid_check_y(struct grid *, u_int);
                     49:
                     50: #ifdef DEBUG
                     51: int
                     52: grid_check_x(struct grid *gd, u_int px)
                     53: {
                     54:        if ((px) >= (gd)->sx)
                     55:                log_fatalx("x out of range: %u", px);
                     56:        return (0);
                     57: }
                     58:
                     59: int
                     60: grid_check_y(struct grid *gd, u_int py)
                     61: {
                     62:        if ((py) >= (gd)->hsize + (gd)->sy)
                     63:                log_fatalx("y out of range: %u", py);
                     64:        return (0);
                     65: }
                     66: #else
                     67: int
                     68: grid_check_x(struct grid *gd, u_int px)
                     69: {
                     70:        if ((px) >= (gd)->sx) {
                     71:                log_debug("x out of range: %u", px);
                     72:                return (-1);
                     73:        }
                     74:        return (0);
                     75: }
                     76:
                     77: int
                     78: grid_check_y(struct grid *gd, u_int py)
                     79: {
                     80:        if ((py) >= (gd)->hsize + (gd)->sy) {
                     81:                log_debug("y out of range: %u", py);
                     82:                return (-1);
                     83:        }
                     84:        return (0);
                     85: }
                     86: #endif
                     87:
                     88: /* Create a new grid. */
                     89: struct grid *
                     90: grid_create(u_int sx, u_int sy, u_int hlimit)
                     91: {
                     92:        struct grid     *gd;
                     93:
                     94:        gd = xmalloc(sizeof *gd);
                     95:        gd->sx = sx;
                     96:        gd->sy = sy;
                     97:
1.7     ! nicm       98:        gd->flags = GRID_HISTORY;
        !            99:
1.1       nicm      100:        gd->hsize = 0;
                    101:        gd->hlimit = hlimit;
                    102:
                    103:        gd->size = xcalloc(gd->sy, sizeof *gd->size);
                    104:        gd->data = xcalloc(gd->sy, sizeof *gd->data);
                    105:
                    106:        gd->usize = xcalloc(gd->sy, sizeof *gd->usize);
                    107:        gd->udata = xcalloc(gd->sy, sizeof *gd->udata);
                    108:
                    109:        return (gd);
                    110: }
                    111:
                    112: /* Destroy grid. */
                    113: void
                    114: grid_destroy(struct grid *gd)
                    115: {
                    116:        u_int   yy;
                    117:
                    118:        for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
                    119:                if (gd->udata[yy] != NULL)
                    120:                        xfree(gd->udata[yy]);
                    121:                if (gd->data[yy] != NULL)
                    122:                        xfree(gd->data[yy]);
                    123:        }
                    124:
                    125:        if (gd->udata != NULL)
                    126:                xfree(gd->udata);
                    127:        if (gd->usize != NULL)
                    128:                xfree(gd->usize);
                    129:
                    130:        if (gd->data != NULL)
                    131:                xfree(gd->data);
                    132:        if (gd->size != NULL)
                    133:                xfree(gd->size);
                    134:
                    135:        xfree(gd);
                    136: }
                    137:
                    138: /* Compare grids. */
                    139: int
                    140: grid_compare(struct grid *ga, struct grid *gb)
                    141: {
                    142:        struct grid_cell        *gca, *gcb;
                    143:        struct grid_utf8        *gua, *gub;
                    144:        u_int                    xx, yy;
                    145:
                    146:        if (ga->sx != gb->sx || ga->sy != ga->sy)
                    147:                return (1);
                    148:
                    149:        for (yy = 0; yy < ga->sy; yy++) {
                    150:                if (ga->size[yy] != gb->size[yy])
                    151:                        return (1);
                    152:                for (xx = 0; xx < ga->sx; xx++) {
                    153:                        gca = &ga->data[yy][xx];
                    154:                        gcb = &gb->data[yy][xx];
                    155:                        if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0)
                    156:                                return (1);
                    157:                        if (!(gca->flags & GRID_FLAG_UTF8))
                    158:                                continue;
                    159:                        gua = &ga->udata[yy][xx];
                    160:                        gub = &gb->udata[yy][xx];
                    161:                        if (memcmp(gua, gub, sizeof (struct grid_utf8)) != 0)
                    162:                                return (1);
                    163:                }
                    164:        }
                    165:
                    166:        return (0);
                    167: }
                    168:
                    169: /* Scroll a line into the history. */
                    170: void
                    171: grid_scroll_line(struct grid *gd)
                    172: {
                    173:        u_int   yy;
                    174:
                    175:        GRID_DEBUG(gd, "");
                    176:
1.6       nicm      177:        if (gd->hsize >= gd->hlimit) {
1.1       nicm      178:                /* If the limit is hit, free the bottom 10% and shift up. */
                    179:                yy = gd->hlimit / 10;
                    180:                if (yy < 1)
                    181:                        yy = 1;
                    182:
                    183:                grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
                    184:                gd->hsize -= yy;
                    185:        }
                    186:
                    187:        yy = gd->hsize + gd->sy;
                    188:
                    189:        gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size);
                    190:        gd->size[yy] = 0;
                    191:        gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data);
                    192:        gd->data[yy] = NULL;
                    193:
                    194:        gd->usize = xrealloc(gd->usize, yy + 1, sizeof *gd->usize);
                    195:        gd->usize[yy] = 0;
                    196:        gd->udata = xrealloc(gd->udata, yy + 1, sizeof *gd->udata);
                    197:        gd->udata[yy] = NULL;
                    198:
                    199:        gd->hsize++;
                    200: }
                    201:
                    202: /* Reduce line to fit to cell. */
                    203: void
                    204: grid_reduce_line(struct grid *gd, u_int py, u_int sx)
                    205: {
                    206:        if (sx < gd->size[py]) {
                    207:                gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data);
                    208:                gd->size[py] = sx;
                    209:        }
                    210:        if (sx < gd->usize[py]) {
                    211:                gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata);
                    212:                gd->usize[py] = sx;
                    213:        }
                    214: }
                    215:
                    216: /* Expand line to fit to cell. */
                    217: void
                    218: grid_expand_line(struct grid *gd, u_int py, u_int sx)
                    219: {
                    220:        u_int   xx;
                    221:
                    222:        if (sx <= gd->size[py])
                    223:                return;
                    224:
                    225:        gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data);
                    226:        for (xx = gd->size[py]; xx < sx; xx++)
                    227:                grid_put_cell(gd, xx, py, &grid_default_cell);
                    228:        gd->size[py] = sx;
                    229: }
                    230:
                    231: /* Expand line to fit to cell for UTF-8. */
                    232: void
                    233: grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
                    234: {
                    235:        if (sx <= gd->usize[py])
                    236:                return;
                    237:
                    238:        gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata);
                    239:        gd->usize[py] = sx;
                    240: }
                    241:
                    242: /* Get cell for reading. */
                    243: const struct grid_cell *
                    244: grid_peek_cell(struct grid *gd, u_int px, u_int py)
                    245: {
                    246:        if (grid_check_x(gd, px) != 0)
                    247:                return (&grid_default_cell);
                    248:        if (grid_check_y(gd, py) != 0)
                    249:                return (&grid_default_cell);
                    250:
                    251:        if (px >= gd->size[py])
                    252:                return (&grid_default_cell);
                    253:        return (&gd->data[py][px]);
                    254: }
                    255:
                    256: /* Get cell at relative position (for writing). */
                    257: struct grid_cell *
                    258: grid_get_cell(struct grid *gd, u_int px, u_int py)
                    259: {
                    260:        if (grid_check_x(gd, px) != 0)
                    261:                return (NULL);
                    262:        if (grid_check_y(gd, py) != 0)
                    263:                return (NULL);
                    264:
                    265:        grid_expand_line(gd, py, px + 1);
                    266:        return (&gd->data[py][px]);
                    267: }
                    268:
                    269: /* Set cell at relative position. */
                    270: void
                    271: grid_set_cell(
                    272:     struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
                    273: {
                    274:        if (grid_check_x(gd, px) != 0)
                    275:                return;
                    276:        if (grid_check_y(gd, py) != 0)
                    277:                return;
                    278:
                    279:        grid_expand_line(gd, py, px + 1);
                    280:        grid_put_cell(gd, px, py, gc);
                    281: }
                    282:
                    283: /* Get UTF-8 for reading. */
                    284: const struct grid_utf8 *
                    285: grid_peek_utf8(struct grid *gd, u_int px, u_int py)
                    286: {
                    287:        if (grid_check_x(gd, px) != 0)
                    288:                return (NULL);
                    289:        if (grid_check_y(gd, py) != 0)
                    290:                return (NULL);
                    291:
                    292:        if (px >= gd->usize[py])
                    293:                return (NULL);
                    294:        return (&gd->udata[py][px]);
                    295: }
                    296:
                    297: /* Get utf8 at relative position (for writing). */
                    298: struct grid_utf8 *
                    299: grid_get_utf8(struct grid *gd, u_int px, u_int py)
                    300: {
                    301:        if (grid_check_x(gd, px) != 0)
                    302:                return (NULL);
                    303:        if (grid_check_y(gd, py) != 0)
                    304:                return (NULL);
                    305:
                    306:        grid_expand_line_utf8(gd, py, px + 1);
                    307:        return (&gd->udata[py][px]);
                    308: }
                    309:
                    310: /* Set utf8 at relative position. */
                    311: void
                    312: grid_set_utf8(
                    313:     struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
                    314: {
                    315:        if (grid_check_x(gd, px) != 0)
                    316:                return;
                    317:        if (grid_check_y(gd, py) != 0)
                    318:                return;
                    319:
                    320:        grid_expand_line_utf8(gd, py, px + 1);
                    321:        grid_put_utf8(gd, px, py, gc);
                    322: }
                    323:
                    324: /*
                    325:  * Clear area. Note this is different from a fill as it just omits unallocated
                    326:  * cells.
                    327:  */
                    328: void
                    329: grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
                    330: {
                    331:        u_int   xx, yy;
                    332:
                    333:        GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny);
                    334:
                    335:        if (nx == 0 || ny == 0)
                    336:                return;
                    337:
                    338:        if (px == 0 && nx == gd->sx) {
                    339:                grid_clear_lines(gd, py, ny);
                    340:                return;
                    341:        }
                    342:
                    343:        if (grid_check_x(gd, px) != 0)
                    344:                return;
                    345:        if (grid_check_x(gd, px + nx - 1) != 0)
                    346:                return;
                    347:        if (grid_check_y(gd, py) != 0)
                    348:                return;
                    349:        if (grid_check_y(gd, py + ny - 1) != 0)
                    350:                return;
                    351:
                    352:        for (yy = py; yy < py + ny; yy++) {
                    353:                for (xx = px; xx < px + nx; xx++) {
                    354:                        if (xx >= gd->size[yy])
                    355:                                break;
                    356:                        grid_put_cell(gd, xx, yy, &grid_default_cell);
                    357:                }
                    358:        }
                    359: }
                    360:
                    361: /* Clear lines. This just frees and truncates the lines. */
                    362: void
                    363: grid_clear_lines(struct grid *gd, u_int py, u_int ny)
                    364: {
                    365:        u_int   yy;
                    366:
                    367:        GRID_DEBUG(gd, "py=%u, ny=%u", py, ny);
                    368:
                    369:        if (ny == 0)
                    370:                return;
                    371:
                    372:        if (grid_check_y(gd, py) != 0)
                    373:                return;
                    374:        if (grid_check_y(gd, py + ny - 1) != 0)
                    375:                return;
                    376:
                    377:        for (yy = py; yy < py + ny; yy++) {
                    378:                if (gd->data[yy] != NULL) {
                    379:                        xfree(gd->data[yy]);
                    380:                        gd->data[yy] = NULL;
                    381:                        gd->size[yy] = 0;
                    382:                }
                    383:                if (gd->udata[yy] != NULL) {
                    384:                        xfree(gd->udata[yy]);
                    385:                        gd->udata[yy] = NULL;
                    386:                        gd->usize[yy] = 0;
                    387:                }
                    388:        }
                    389: }
                    390:
                    391: /* Move a group of lines. */
                    392: void
                    393: grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny)
                    394: {
                    395:        u_int   yy;
                    396:
                    397:        GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny);
                    398:
                    399:        if (ny == 0 || py == dy)
                    400:                return;
                    401:
                    402:        if (grid_check_y(gd, py) != 0)
                    403:                return;
                    404:        if (grid_check_y(gd, py + ny - 1) != 0)
                    405:                return;
                    406:        if (grid_check_y(gd, dy) != 0)
                    407:                return;
                    408:        if (grid_check_y(gd, dy + ny - 1) != 0)
                    409:                return;
                    410:
                    411:        /* Free any lines which are being replaced. */
                    412:        for (yy = dy; yy < dy + ny; yy++) {
                    413:                if (yy >= py && yy < py + ny)
                    414:                        continue;
                    415:                grid_clear_lines(gd, yy, 1);
                    416:        }
                    417:
                    418:        memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data));
                    419:        memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size));
                    420:
                    421:        memmove(&gd->udata[dy], &gd->udata[py], ny * (sizeof *gd->udata));
                    422:        memmove(&gd->usize[dy], &gd->usize[py], ny * (sizeof *gd->usize));
                    423:
                    424:        /* Wipe any lines that have been moved (without freeing them). */
                    425:        for (yy = py; yy < py + ny; yy++) {
                    426:                if (yy >= dy && yy < dy + ny)
                    427:                        continue;
                    428:                gd->data[yy] = NULL;
                    429:                gd->size[yy] = 0;
                    430:                gd->udata[yy] = NULL;
                    431:                gd->usize[yy] = 0;
                    432:        }
                    433: }
                    434:
                    435: /* Move a group of cells. */
                    436: void
                    437: grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
                    438: {
                    439:        u_int   xx;
                    440:
                    441:        GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx);
                    442:
                    443:        if (nx == 0 || px == dx)
                    444:                return;
                    445:
                    446:        if (grid_check_x(gd, px) != 0)
                    447:                return;
                    448:        if (grid_check_x(gd, px + nx - 1) != 0)
                    449:                return;
                    450:        if (grid_check_x(gd, dx + nx - 1) != 0)
                    451:                return;
                    452:        if (grid_check_y(gd, py) != 0)
                    453:                return;
                    454:
                    455:        grid_expand_line(gd, py, px + nx);
                    456:        grid_expand_line(gd, py, dx + nx);
                    457:        memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data));
                    458:
                    459:        if (gd->udata[py] != NULL) {
                    460:                grid_expand_line_utf8(gd, py, px + nx);
                    461:                grid_expand_line_utf8(gd, py, dx + nx);
                    462:                memmove(&gd->udata[py][dx],
                    463:                    &gd->udata[py][px], nx * (sizeof **gd->udata));
                    464:        }
                    465:
                    466:        /* Wipe any cells that have been moved. */
                    467:        for (xx = px; xx < px + nx; xx++) {
                    468:                if (xx >= dx && xx < dx + nx)
                    469:                        continue;
                    470:                grid_put_cell(gd, xx, py, &grid_default_cell);
                    471:        }
1.3       nicm      472: }
                    473:
                    474: /* Convert cells into a string. */
                    475: char *
                    476: grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
                    477: {
                    478:        const struct grid_cell  *gc;
                    479:        const struct grid_utf8  *gu;
                    480:        char                    *buf;
                    481:        size_t                   len, off;
1.4       nicm      482:        u_int                    xx, i;
1.3       nicm      483:
                    484:        GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
                    485:
                    486:        len = 128;
                    487:        buf = xmalloc(len);
                    488:        off = 0;
                    489:
                    490:        for (xx = px; xx < px + nx; xx++) {
                    491:                gc = grid_peek_cell(gd, xx, py);
                    492:                if (gc->flags & GRID_FLAG_PADDING)
                    493:                        continue;
                    494:
                    495:                if (gc->flags & GRID_FLAG_UTF8) {
                    496:                        while (len < off + UTF8_SIZE + 1) {
                    497:                                buf = xrealloc(buf, 2, len);
                    498:                                len *= 2;
                    499:                        }
                    500:
                    501:                        gu = grid_peek_utf8(gd, xx, py);
1.4       nicm      502:                        for (i = 0; i < UTF8_SIZE; i++) {
                    503:                                if (gu->data[i] == 0xff)
                    504:                                        break;
                    505:                                buf[off++] = gu->data[i];
                    506:                        }
1.3       nicm      507:                } else {
                    508:                        while (len < off + 2) {
                    509:                                buf = xrealloc(buf, 2, len);
                    510:                                len *= 2;
                    511:                        }
                    512:
                    513:                        buf[off++] = gc->data;
                    514:                }
                    515:        }
1.4       nicm      516:
                    517:        while (off > 0 && buf[off - 1] == ' ')
                    518:                off--;
1.3       nicm      519:        buf[off] = '\0';
                    520:        return (buf);
1.7     ! nicm      521: }
        !           522:
        !           523: /*
        !           524:  * Duplicate a set of lines between two grids. If there aren't enough lines in
        !           525:  * either source or destination, the number of lines is limited to the number
        !           526:  * available.
        !           527:  */
        !           528: void
        !           529: grid_duplicate_lines(
        !           530:     struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny)
        !           531: {
        !           532:        u_int   yy;
        !           533:
        !           534:        GRID_DEBUG(src, "dy=%u, sy=%u, ny=%u", dy, sy, ny);
        !           535:
        !           536:        if (dy + ny > dst->hsize + dst->sy)
        !           537:                ny = dst->hsize + dst->sy - dy;
        !           538:        if (sy + ny > src->hsize + src->sy)
        !           539:                ny = src->hsize + src->sy - sy;
        !           540:        grid_clear_lines(dst, dy, ny);
        !           541:
        !           542:        for (yy = 0; yy < ny; yy++) {
        !           543:                dst->size[dy] = src->size[sy];
        !           544:                if (src->size[sy] == 0)
        !           545:                        dst->data[dy] = NULL;
        !           546:                else {
        !           547:                        dst->data[dy] = xcalloc(
        !           548:                            src->size[sy], sizeof **dst->data);
        !           549:                        memcpy(dst->data[dy], src->data[sy],
        !           550:                            src->size[sy] * (sizeof **dst->data));
        !           551:                }
        !           552:
        !           553:                dst->usize[dy] = src->usize[sy];
        !           554:                if (src->usize[sy] == 0)
        !           555:                        dst->udata[dy] = NULL;
        !           556:                else {
        !           557:                        dst->udata[sy] = xcalloc(
        !           558:                            src->usize[sy], sizeof **dst->udata);
        !           559:                        memcpy(dst->udata[dy], src->udata[sy],
        !           560:                            src->usize[sy] * (sizeof **dst->udata));
        !           561:                }
        !           562:
        !           563:                sy++; dy++;
        !           564:        }
1.1       nicm      565: }