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

Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.76

1.76    ! nicm        1: /* $OpenBSD: screen-write.c,v 1.75 2015/11/12 11:09:11 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2007 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:
1.56      nicm       21: #include <stdlib.h>
1.1       nicm       22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
1.31      nicm       26: void   screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
1.43      nicm       27: void   screen_write_overwrite(struct screen_write_ctx *, u_int);
1.71      nicm       28: int    screen_write_combine(struct screen_write_ctx *,
                     29:            const struct utf8_data *);
1.1       nicm       30:
                     31: /* Initialise writing with a window. */
                     32: void
1.71      nicm       33: screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
                     34:     struct screen *s)
1.1       nicm       35: {
                     36:        ctx->wp = wp;
                     37:        if (wp != NULL && s == NULL)
                     38:                ctx->s = wp->screen;
                     39:        else
                     40:                ctx->s = s;
                     41: }
                     42:
                     43: /* Finish writing. */
                     44: void
                     45: screen_write_stop(unused struct screen_write_ctx *ctx)
                     46: {
1.52      nicm       47: }
                     48:
                     49: /* Reset screen state. */
                     50: void
                     51: screen_write_reset(struct screen_write_ctx *ctx)
                     52: {
1.61      nicm       53:        struct screen   *s = ctx->s;
1.52      nicm       54:
1.61      nicm       55:        screen_reset_tabs(s);
                     56:        screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
1.63      nicm       57:
1.67      nicm       58:        s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
1.63      nicm       59:        s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
1.52      nicm       60:
                     61:        screen_write_clearscreen(ctx);
                     62:        screen_write_cursormove(ctx, 0, 0);
1.1       nicm       63: }
                     64:
                     65: /* Write character. */
                     66: void
1.69      nicm       67: screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc,
                     68:     u_char ch)
1.1       nicm       69: {
1.60      nicm       70:        grid_cell_one(gc, ch);
                     71:        screen_write_cell(ctx, gc);
1.1       nicm       72: }
                     73:
1.24      nicm       74: /* Calculate string length, with embedded formatting. */
1.71      nicm       75: size_t
1.75      nicm       76: screen_write_cstrlen(const char *fmt, ...)
1.24      nicm       77: {
                     78:        va_list ap;
                     79:        char   *msg, *msg2, *ptr, *ptr2;
                     80:        size_t  size;
                     81:
                     82:        va_start(ap, fmt);
                     83:        xvasprintf(&msg, fmt, ap);
                     84:        va_end(ap);
                     85:        msg2 = xmalloc(strlen(msg) + 1);
                     86:
                     87:        ptr = msg;
                     88:        ptr2 = msg2;
                     89:        while (*ptr != '\0') {
                     90:                if (ptr[0] == '#' && ptr[1] == '[') {
                     91:                        while (*ptr != ']' && *ptr != '\0')
                     92:                                ptr++;
                     93:                        if (*ptr == ']')
                     94:                                ptr++;
                     95:                        continue;
                     96:                }
                     97:                *ptr2++ = *ptr++;
                     98:        }
                     99:        *ptr2 = '\0';
                    100:
1.75      nicm      101:        size = screen_write_strlen("%s", msg2);
1.24      nicm      102:
1.56      nicm      103:        free(msg);
                    104:        free(msg2);
1.24      nicm      105:
                    106:        return (size);
                    107: }
                    108:
1.2       nicm      109: /* Calculate string length. */
1.71      nicm      110: size_t
1.75      nicm      111: screen_write_strlen(const char *fmt, ...)
1.2       nicm      112: {
1.36      nicm      113:        va_list                 ap;
                    114:        char                   *msg;
1.76    ! nicm      115:        struct utf8_data        ud;
1.36      nicm      116:        u_char                 *ptr;
                    117:        size_t                  left, size = 0;
1.2       nicm      118:
                    119:        va_start(ap, fmt);
                    120:        xvasprintf(&msg, fmt, ap);
                    121:        va_end(ap);
                    122:
                    123:        ptr = msg;
                    124:        while (*ptr != '\0') {
1.76    ! nicm      125:                if (*ptr > 0x7f && utf8_open(&ud, *ptr)) {
1.36      nicm      126:                        ptr++;
1.2       nicm      127:
                    128:                        left = strlen(ptr);
1.76    ! nicm      129:                        if (left < ud.size - 1)
1.36      nicm      130:                                break;
1.76    ! nicm      131:                        while (utf8_append(&ud, *ptr))
1.2       nicm      132:                                ptr++;
1.36      nicm      133:                        ptr++;
                    134:
1.76    ! nicm      135:                        size += ud.width;
1.2       nicm      136:                } else {
1.75      nicm      137:                        if (*ptr > 0x1f && *ptr < 0x7f)
                    138:                                size++;
1.2       nicm      139:                        ptr++;
                    140:                }
1.7       ray       141:        }
1.2       nicm      142:
1.56      nicm      143:        free(msg);
1.2       nicm      144:        return (size);
                    145: }
                    146:
1.3       nicm      147: /* Write simple string (no UTF-8 or maximum length). */
1.71      nicm      148: void
                    149: screen_write_puts(struct screen_write_ctx *ctx, struct grid_cell *gc,
                    150:     const char *fmt, ...)
1.1       nicm      151: {
                    152:        va_list ap;
                    153:
                    154:        va_start(ap, fmt);
1.75      nicm      155:        screen_write_vnputs(ctx, -1, gc, fmt, ap);
1.2       nicm      156:        va_end(ap);
                    157: }
                    158:
                    159: /* Write string with length limit (-1 for unlimited). */
1.71      nicm      160: void
                    161: screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.75      nicm      162:     struct grid_cell *gc, const char *fmt, ...)
1.2       nicm      163: {
                    164:        va_list ap;
                    165:
                    166:        va_start(ap, fmt);
1.75      nicm      167:        screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
1.2       nicm      168:        va_end(ap);
                    169: }
                    170:
                    171: void
1.3       nicm      172: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.75      nicm      173:     struct grid_cell *gc, const char *fmt, va_list ap)
1.2       nicm      174: {
1.36      nicm      175:        char                   *msg;
1.76    ! nicm      176:        struct utf8_data        ud;
1.36      nicm      177:        u_char                 *ptr;
                    178:        size_t                  left, size = 0;
1.2       nicm      179:
1.1       nicm      180:        xvasprintf(&msg, fmt, ap);
                    181:
1.2       nicm      182:        ptr = msg;
                    183:        while (*ptr != '\0') {
1.76    ! nicm      184:                if (*ptr > 0x7f && utf8_open(&ud, *ptr)) {
1.36      nicm      185:                        ptr++;
1.2       nicm      186:
                    187:                        left = strlen(ptr);
1.76    ! nicm      188:                        if (left < ud.size - 1)
1.36      nicm      189:                                break;
1.76    ! nicm      190:                        while (utf8_append(&ud, *ptr))
1.2       nicm      191:                                ptr++;
1.36      nicm      192:                        ptr++;
1.7       ray       193:
1.36      nicm      194:                        if (maxlen > 0 &&
1.76    ! nicm      195:                            size + ud.width > (size_t) maxlen) {
1.2       nicm      196:                                while (size < (size_t) maxlen) {
                    197:                                        screen_write_putc(ctx, gc, ' ');
                    198:                                        size++;
                    199:                                }
                    200:                                break;
                    201:                        }
1.76    ! nicm      202:                        size += ud.width;
1.41      nicm      203:
1.76    ! nicm      204:                        grid_cell_set(gc, &ud);
1.60      nicm      205:                        screen_write_cell(ctx, gc);
1.2       nicm      206:                } else {
1.8       nicm      207:                        if (maxlen > 0 && size + 1 > (size_t) maxlen)
1.2       nicm      208:                                break;
                    209:
1.57      nicm      210:                        if (*ptr == '\001')
                    211:                                gc->attr ^= GRID_ATTR_CHARSET;
1.75      nicm      212:                        else if (*ptr > 0x1f && *ptr < 0x7f) {
1.57      nicm      213:                                size++;
                    214:                                screen_write_putc(ctx, gc, *ptr);
                    215:                        }
1.2       nicm      216:                        ptr++;
                    217:                }
                    218:        }
1.1       nicm      219:
1.56      nicm      220:        free(msg);
1.24      nicm      221: }
                    222:
                    223: /* Write string, similar to nputs, but with embedded formatting (#[]). */
1.71      nicm      224: void
1.75      nicm      225: screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
                    226:     struct grid_cell *gc, const char *fmt, ...)
1.24      nicm      227: {
                    228:        struct grid_cell         lgc;
1.76    ! nicm      229:        struct utf8_data         ud;
1.24      nicm      230:        va_list                  ap;
                    231:        char                    *msg;
1.36      nicm      232:        u_char                  *ptr, *last;
1.24      nicm      233:        size_t                   left, size = 0;
                    234:
                    235:        va_start(ap, fmt);
                    236:        xvasprintf(&msg, fmt, ap);
                    237:        va_end(ap);
                    238:
                    239:        memcpy(&lgc, gc, sizeof lgc);
                    240:
                    241:        ptr = msg;
                    242:        while (*ptr != '\0') {
                    243:                if (ptr[0] == '#' && ptr[1] == '[') {
                    244:                        ptr += 2;
                    245:                        last = ptr + strcspn(ptr, "]");
                    246:                        if (*last == '\0') {
                    247:                                /* No ]. Not much point in doing anything. */
                    248:                                break;
                    249:                        }
                    250:                        *last = '\0';
                    251:
1.68      nicm      252:                        style_parse(gc, &lgc, ptr);
1.24      nicm      253:                        ptr = last + 1;
                    254:                        continue;
                    255:                }
                    256:
1.76    ! nicm      257:                if (*ptr > 0x7f && utf8_open(&ud, *ptr)) {
1.36      nicm      258:                        ptr++;
1.24      nicm      259:
                    260:                        left = strlen(ptr);
1.76    ! nicm      261:                        if (left < ud.size - 1)
1.36      nicm      262:                                break;
1.76    ! nicm      263:                        while (utf8_append(&ud, *ptr))
1.24      nicm      264:                                ptr++;
1.36      nicm      265:                        ptr++;
1.24      nicm      266:
1.36      nicm      267:                        if (maxlen > 0 &&
1.76    ! nicm      268:                            size + ud.width > (size_t) maxlen) {
1.24      nicm      269:                                while (size < (size_t) maxlen) {
                    270:                                        screen_write_putc(ctx, gc, ' ');
                    271:                                        size++;
                    272:                                }
                    273:                                break;
                    274:                        }
1.76    ! nicm      275:                        size += ud.width;
1.24      nicm      276:
1.76    ! nicm      277:                        grid_cell_set(&lgc, &ud);
1.60      nicm      278:                        screen_write_cell(ctx, &lgc);
1.24      nicm      279:                } else {
                    280:                        if (maxlen > 0 && size + 1 > (size_t) maxlen)
                    281:                                break;
                    282:
1.75      nicm      283:                        if (*ptr > 0x1f && *ptr < 0x7f) {
                    284:                                size++;
                    285:                                screen_write_putc(ctx, &lgc, *ptr);
                    286:                        }
1.24      nicm      287:                        ptr++;
                    288:                }
                    289:        }
                    290:
1.56      nicm      291:        free(msg);
1.1       nicm      292: }
                    293:
                    294: /* Copy from another screen. */
                    295: void
                    296: screen_write_copy(struct screen_write_ctx *ctx,
                    297:     struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
                    298: {
                    299:        struct screen           *s = ctx->s;
                    300:        struct grid             *gd = src->grid;
1.21      nicm      301:        struct grid_line        *gl;
1.1       nicm      302:        const struct grid_cell  *gc;
1.60      nicm      303:        struct utf8_data         ud;
1.39      nicm      304:        u_int                    xx, yy, cx, cy, ax, bx;
1.1       nicm      305:
                    306:        cx = s->cx;
                    307:        cy = s->cy;
                    308:        for (yy = py; yy < py + ny; yy++) {
1.21      nicm      309:                gl = &gd->linedata[yy];
1.26      nicm      310:                if (yy < gd->hsize + gd->sy) {
                    311:                        /*
                    312:                         * Find start and end position and copy between
                    313:                         * them. Limit to the real end of the line then use a
                    314:                         * clear EOL only if copying to the end, otherwise
                    315:                         * could overwrite whatever is there already.
                    316:                         */
                    317:                        if (px > gl->cellsize)
                    318:                                ax = gl->cellsize;
                    319:                        else
                    320:                                ax = px;
                    321:                        if (px + nx == gd->sx && px + nx > gl->cellsize)
                    322:                                bx = gl->cellsize;
                    323:                        else
                    324:                                bx = px + nx;
1.41      nicm      325:
1.26      nicm      326:                        for (xx = ax; xx < bx; xx++) {
                    327:                                if (xx >= gl->cellsize)
                    328:                                        gc = &grid_default_cell;
1.36      nicm      329:                                else
1.26      nicm      330:                                        gc = &gl->celldata[xx];
1.60      nicm      331:                                grid_cell_get(gc, &ud);
                    332:                                screen_write_cell(ctx, gc);
1.1       nicm      333:                        }
1.26      nicm      334:                        if (px + nx == gd->sx && px + nx > gl->cellsize)
                    335:                                screen_write_clearendofline(ctx);
                    336:                } else
1.36      nicm      337:                        screen_write_clearline(ctx);
1.1       nicm      338:                cy++;
                    339:                screen_write_cursormove(ctx, cx, cy);
                    340:        }
                    341: }
                    342:
1.17      nicm      343: /* Set up context for TTY command. */
1.1       nicm      344: void
1.31      nicm      345: screen_write_initctx(
                    346:     struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, int save_last)
1.1       nicm      347: {
1.31      nicm      348:        struct screen           *s = ctx->s;
                    349:        struct grid             *gd = s->grid;
                    350:        const struct grid_cell  *gc;
                    351:        u_int                    xx;
1.1       nicm      352:
1.17      nicm      353:        ttyctx->wp = ctx->wp;
1.1       nicm      354:
1.17      nicm      355:        ttyctx->ocx = s->cx;
                    356:        ttyctx->ocy = s->cy;
                    357:
                    358:        ttyctx->orlower = s->rlower;
                    359:        ttyctx->orupper = s->rupper;
1.31      nicm      360:
                    361:        if (!save_last)
                    362:                return;
                    363:
                    364:        /* Save the last cell on the screen. */
1.38      nicm      365:        gc = &grid_default_cell;
                    366:        for (xx = 1; xx <= screen_size_x(s); xx++) {
1.31      nicm      367:                gc = grid_view_peek_cell(gd, screen_size_x(s) - xx, s->cy);
                    368:                if (!(gc->flags & GRID_FLAG_PADDING))
                    369:                        break;
                    370:        }
                    371:        ttyctx->last_width = xx;
                    372:        memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell);
1.1       nicm      373: }
                    374:
1.61      nicm      375: /* Set a mode. */
                    376: void
                    377: screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
                    378: {
                    379:        struct screen   *s = ctx->s;
                    380:
                    381:        s->mode |= mode;
                    382: }
                    383:
                    384: /* Clear a mode. */
                    385: void
                    386: screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
                    387: {
                    388:        struct screen   *s = ctx->s;
                    389:
                    390:        s->mode &= ~mode;
                    391: }
                    392:
1.1       nicm      393: /* Cursor up by ny. */
                    394: void
                    395: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
                    396: {
                    397:        struct screen   *s = ctx->s;
                    398:
                    399:        if (ny == 0)
                    400:                ny = 1;
                    401:
1.12      nicm      402:        if (s->cy < s->rupper) {
                    403:                /* Above region. */
                    404:                if (ny > s->cy)
                    405:                        ny = s->cy;
                    406:        } else {
                    407:                /* Below region. */
                    408:                if (ny > s->cy - s->rupper)
                    409:                        ny = s->cy - s->rupper;
                    410:        }
1.66      nicm      411:        if (s->cx == screen_size_x(s))
                    412:            s->cx--;
1.1       nicm      413:        if (ny == 0)
                    414:                return;
                    415:
                    416:        s->cy -= ny;
                    417: }
                    418:
                    419: /* Cursor down by ny. */
                    420: void
                    421: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
                    422: {
                    423:        struct screen   *s = ctx->s;
                    424:
                    425:        if (ny == 0)
                    426:                ny = 1;
                    427:
1.12      nicm      428:        if (s->cy > s->rlower) {
                    429:                /* Below region. */
                    430:                if (ny > screen_size_y(s) - 1 - s->cy)
                    431:                        ny = screen_size_y(s) - 1 - s->cy;
                    432:        } else {
                    433:                /* Above region. */
                    434:                if (ny > s->rlower - s->cy)
                    435:                        ny = s->rlower - s->cy;
                    436:        }
1.66      nicm      437:        if (s->cx == screen_size_x(s))
                    438:            s->cx--;
1.1       nicm      439:        if (ny == 0)
                    440:                return;
                    441:
                    442:        s->cy += ny;
                    443: }
                    444:
                    445: /* Cursor right by nx.  */
                    446: void
                    447: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
                    448: {
                    449:        struct screen   *s = ctx->s;
                    450:
                    451:        if (nx == 0)
                    452:                nx = 1;
                    453:
                    454:        if (nx > screen_size_x(s) - 1 - s->cx)
                    455:                nx = screen_size_x(s) - 1 - s->cx;
                    456:        if (nx == 0)
                    457:                return;
                    458:
                    459:        s->cx += nx;
                    460: }
                    461:
                    462: /* Cursor left by nx. */
                    463: void
                    464: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
                    465: {
                    466:        struct screen   *s = ctx->s;
                    467:
                    468:        if (nx == 0)
                    469:                nx = 1;
                    470:
                    471:        if (nx > s->cx)
                    472:                nx = s->cx;
                    473:        if (nx == 0)
                    474:                return;
                    475:
                    476:        s->cx -= nx;
1.5       nicm      477: }
                    478:
1.29      nicm      479: /* Backspace; cursor left unless at start of wrapped line when can move up. */
                    480: void
                    481: screen_write_backspace(struct screen_write_ctx *ctx)
                    482: {
                    483:        struct screen           *s = ctx->s;
                    484:        struct grid_line        *gl;
                    485:
                    486:        if (s->cx == 0) {
                    487:                if (s->cy == 0)
                    488:                        return;
                    489:                gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
                    490:                if (gl->flags & GRID_LINE_WRAPPED) {
                    491:                        s->cy--;
                    492:                        s->cx = screen_size_x(s) - 1;
                    493:                }
                    494:        } else
                    495:                s->cx--;
                    496: }
                    497:
1.5       nicm      498: /* VT100 alignment test. */
                    499: void
                    500: screen_write_alignmenttest(struct screen_write_ctx *ctx)
                    501: {
                    502:        struct screen           *s = ctx->s;
1.17      nicm      503:        struct tty_ctx           ttyctx;
1.5       nicm      504:        struct grid_cell         gc;
                    505:        u_int                    xx, yy;
                    506:
1.31      nicm      507:        screen_write_initctx(ctx, &ttyctx, 0);
1.17      nicm      508:
1.5       nicm      509:        memcpy(&gc, &grid_default_cell, sizeof gc);
1.60      nicm      510:        grid_cell_one(&gc, 'E');
1.7       ray       511:
1.5       nicm      512:        for (yy = 0; yy < screen_size_y(s); yy++) {
                    513:                for (xx = 0; xx < screen_size_x(s); xx++)
                    514:                        grid_view_set_cell(s->grid, xx, yy, &gc);
                    515:        }
1.7       ray       516:
1.5       nicm      517:        s->cx = 0;
                    518:        s->cy = 0;
                    519:
                    520:        s->rupper = 0;
1.29      nicm      521:
1.5       nicm      522:        s->rlower = screen_size_y(s) - 1;
                    523:
1.17      nicm      524:        tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1       nicm      525: }
                    526:
                    527: /* Insert nx characters. */
                    528: void
                    529: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
                    530: {
                    531:        struct screen   *s = ctx->s;
1.17      nicm      532:        struct tty_ctx   ttyctx;
1.1       nicm      533:
                    534:        if (nx == 0)
                    535:                nx = 1;
                    536:
1.9       nicm      537:        if (nx > screen_size_x(s) - s->cx)
                    538:                nx = screen_size_x(s) - s->cx;
1.1       nicm      539:        if (nx == 0)
                    540:                return;
                    541:
1.31      nicm      542:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      543:
                    544:        if (s->cx <= screen_size_x(s) - 1)
                    545:                grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
                    546:
1.17      nicm      547:        ttyctx.num = nx;
                    548:        tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1       nicm      549: }
                    550:
                    551: /* Delete nx characters. */
                    552: void
                    553: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
                    554: {
                    555:        struct screen   *s = ctx->s;
1.17      nicm      556:        struct tty_ctx   ttyctx;
1.1       nicm      557:
                    558:        if (nx == 0)
                    559:                nx = 1;
                    560:
1.9       nicm      561:        if (nx > screen_size_x(s) - s->cx)
                    562:                nx = screen_size_x(s) - s->cx;
1.1       nicm      563:        if (nx == 0)
                    564:                return;
                    565:
1.31      nicm      566:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      567:
                    568:        if (s->cx <= screen_size_x(s) - 1)
                    569:                grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
                    570:
1.17      nicm      571:        ttyctx.num = nx;
                    572:        tty_write(tty_cmd_deletecharacter, &ttyctx);
1.59      nicm      573: }
                    574:
                    575: /* Clear nx characters. */
                    576: void
                    577: screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
                    578: {
                    579:        struct screen   *s = ctx->s;
                    580:        struct tty_ctx   ttyctx;
                    581:
                    582:        if (nx == 0)
                    583:                nx = 1;
                    584:
                    585:        if (nx > screen_size_x(s) - s->cx)
                    586:                nx = screen_size_x(s) - s->cx;
                    587:        if (nx == 0)
                    588:                return;
                    589:
                    590:        screen_write_initctx(ctx, &ttyctx, 0);
                    591:
                    592:        if (s->cx <= screen_size_x(s) - 1)
                    593:                grid_view_clear(s->grid, s->cx, s->cy, nx, 1);
                    594:
                    595:        ttyctx.num = nx;
                    596:        tty_write(tty_cmd_clearcharacter, &ttyctx);
1.1       nicm      597: }
                    598:
                    599: /* Insert ny lines. */
                    600: void
                    601: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
                    602: {
                    603:        struct screen   *s = ctx->s;
1.17      nicm      604:        struct tty_ctx   ttyctx;
1.1       nicm      605:
                    606:        if (ny == 0)
                    607:                ny = 1;
                    608:
1.11      nicm      609:        if (s->cy < s->rupper || s->cy > s->rlower) {
                    610:                if (ny > screen_size_y(s) - s->cy)
                    611:                        ny = screen_size_y(s) - s->cy;
                    612:                if (ny == 0)
                    613:                        return;
                    614:
1.31      nicm      615:                screen_write_initctx(ctx, &ttyctx, 0);
1.11      nicm      616:
                    617:                grid_view_insert_lines(s->grid, s->cy, ny);
                    618:
1.17      nicm      619:                ttyctx.num = ny;
                    620:                tty_write(tty_cmd_insertline, &ttyctx);
1.11      nicm      621:                return;
                    622:        }
                    623:
                    624:        if (ny > s->rlower + 1 - s->cy)
                    625:                ny = s->rlower + 1 - s->cy;
1.1       nicm      626:        if (ny == 0)
                    627:                return;
1.41      nicm      628:
1.31      nicm      629:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      630:
                    631:        if (s->cy < s->rupper || s->cy > s->rlower)
                    632:                grid_view_insert_lines(s->grid, s->cy, ny);
1.10      nicm      633:        else
                    634:                grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
1.1       nicm      635:
1.17      nicm      636:        ttyctx.num = ny;
                    637:        tty_write(tty_cmd_insertline, &ttyctx);
1.1       nicm      638: }
                    639:
                    640: /* Delete ny lines. */
                    641: void
                    642: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
                    643: {
                    644:        struct screen   *s = ctx->s;
1.17      nicm      645:        struct tty_ctx   ttyctx;
1.1       nicm      646:
                    647:        if (ny == 0)
                    648:                ny = 1;
                    649:
1.11      nicm      650:        if (s->cy < s->rupper || s->cy > s->rlower) {
                    651:                if (ny > screen_size_y(s) - s->cy)
                    652:                        ny = screen_size_y(s) - s->cy;
                    653:                if (ny == 0)
                    654:                        return;
                    655:
1.31      nicm      656:                screen_write_initctx(ctx, &ttyctx, 0);
1.11      nicm      657:
                    658:                grid_view_delete_lines(s->grid, s->cy, ny);
                    659:
1.17      nicm      660:                ttyctx.num = ny;
                    661:                tty_write(tty_cmd_deleteline, &ttyctx);
1.11      nicm      662:                return;
                    663:        }
1.41      nicm      664:
1.11      nicm      665:        if (ny > s->rlower + 1 - s->cy)
                    666:                ny = s->rlower + 1 - s->cy;
1.1       nicm      667:        if (ny == 0)
                    668:                return;
                    669:
1.31      nicm      670:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      671:
                    672:        if (s->cy < s->rupper || s->cy > s->rlower)
                    673:                grid_view_delete_lines(s->grid, s->cy, ny);
1.10      nicm      674:        else
                    675:                grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
1.1       nicm      676:
1.17      nicm      677:        ttyctx.num = ny;
                    678:        tty_write(tty_cmd_deleteline, &ttyctx);
1.1       nicm      679: }
                    680:
                    681: /* Clear line at cursor. */
                    682: void
                    683: screen_write_clearline(struct screen_write_ctx *ctx)
                    684: {
                    685:        struct screen   *s = ctx->s;
1.17      nicm      686:        struct tty_ctx   ttyctx;
1.1       nicm      687:
1.31      nicm      688:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      689:
                    690:        grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
                    691:
1.17      nicm      692:        tty_write(tty_cmd_clearline, &ttyctx);
1.1       nicm      693: }
                    694:
                    695: /* Clear to end of line from cursor. */
                    696: void
                    697: screen_write_clearendofline(struct screen_write_ctx *ctx)
                    698: {
                    699:        struct screen   *s = ctx->s;
1.17      nicm      700:        struct tty_ctx   ttyctx;
1.1       nicm      701:        u_int            sx;
                    702:
1.31      nicm      703:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      704:
                    705:        sx = screen_size_x(s);
                    706:
                    707:        if (s->cx <= sx - 1)
                    708:                grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
                    709:
1.41      nicm      710:        tty_write(tty_cmd_clearendofline, &ttyctx);
1.1       nicm      711: }
                    712:
                    713: /* Clear to start of line from cursor. */
                    714: void
                    715: screen_write_clearstartofline(struct screen_write_ctx *ctx)
                    716: {
                    717:        struct screen   *s = ctx->s;
1.17      nicm      718:        struct tty_ctx   ttyctx;
1.1       nicm      719:        u_int            sx;
                    720:
1.31      nicm      721:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      722:
                    723:        sx = screen_size_x(s);
                    724:
                    725:        if (s->cx > sx - 1)
                    726:                grid_view_clear(s->grid, 0, s->cy, sx, 1);
                    727:        else
                    728:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
                    729:
1.17      nicm      730:        tty_write(tty_cmd_clearstartofline, &ttyctx);
1.1       nicm      731: }
                    732:
                    733: /* Move cursor to px,py.  */
                    734: void
                    735: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
                    736: {
                    737:        struct screen   *s = ctx->s;
                    738:
                    739:        if (px > screen_size_x(s) - 1)
                    740:                px = screen_size_x(s) - 1;
                    741:        if (py > screen_size_y(s) - 1)
                    742:                py = screen_size_y(s) - 1;
                    743:
                    744:        s->cx = px;
                    745:        s->cy = py;
                    746: }
                    747:
                    748: /* Reverse index (up with scroll).  */
                    749: void
                    750: screen_write_reverseindex(struct screen_write_ctx *ctx)
                    751: {
                    752:        struct screen   *s = ctx->s;
1.17      nicm      753:        struct tty_ctx   ttyctx;
1.1       nicm      754:
1.31      nicm      755:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      756:
                    757:        if (s->cy == s->rupper)
                    758:                grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
                    759:        else if (s->cy > 0)
                    760:                s->cy--;
                    761:
1.17      nicm      762:        tty_write(tty_cmd_reverseindex, &ttyctx);
1.1       nicm      763: }
                    764:
                    765: /* Set scroll region. */
                    766: void
                    767: screen_write_scrollregion(
                    768:     struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
                    769: {
                    770:        struct screen   *s = ctx->s;
                    771:
                    772:        if (rupper > screen_size_y(s) - 1)
                    773:                rupper = screen_size_y(s) - 1;
                    774:        if (rlower > screen_size_y(s) - 1)
                    775:                rlower = screen_size_y(s) - 1;
1.13      nicm      776:        if (rupper >= rlower)   /* cannot be one line */
1.1       nicm      777:                return;
                    778:
                    779:        /* Cursor moves to top-left. */
                    780:        s->cx = 0;
                    781:        s->cy = 0;
                    782:
                    783:        s->rupper = rupper;
                    784:        s->rlower = rlower;
                    785: }
                    786:
1.34      nicm      787: /* Line feed. */
1.1       nicm      788: void
1.34      nicm      789: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
1.1       nicm      790: {
1.20      nicm      791:        struct screen           *s = ctx->s;
                    792:        struct grid_line        *gl;
1.34      nicm      793:        struct tty_ctx           ttyctx;
                    794:
                    795:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      796:
1.20      nicm      797:        gl = &s->grid->linedata[s->grid->hsize + s->cy];
                    798:        if (wrapped)
                    799:                gl->flags |= GRID_LINE_WRAPPED;
1.73      nicm      800:        else
                    801:                gl->flags &= ~GRID_LINE_WRAPPED;
1.20      nicm      802:
1.1       nicm      803:        if (s->cy == s->rlower)
                    804:                grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
                    805:        else if (s->cy < screen_size_y(s) - 1)
                    806:                s->cy++;
                    807:
1.34      nicm      808:        ttyctx.num = wrapped;
1.41      nicm      809:        tty_write(tty_cmd_linefeed, &ttyctx);
1.1       nicm      810: }
                    811:
                    812: /* Carriage return (cursor to start of line). */
                    813: void
                    814: screen_write_carriagereturn(struct screen_write_ctx *ctx)
                    815: {
                    816:        struct screen   *s = ctx->s;
                    817:
                    818:        s->cx = 0;
                    819: }
                    820:
                    821: /* Clear to end of screen from cursor. */
                    822: void
                    823: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
                    824: {
                    825:        struct screen   *s = ctx->s;
1.17      nicm      826:        struct tty_ctx   ttyctx;
1.1       nicm      827:        u_int            sx, sy;
                    828:
1.31      nicm      829:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      830:
                    831:        sx = screen_size_x(s);
                    832:        sy = screen_size_y(s);
                    833:
1.46      nicm      834:        /* Scroll into history if it is enabled and clearing entire screen. */
                    835:        if (s->cy == 0 && s->grid->flags & GRID_HISTORY)
                    836:                grid_view_clear_history(s->grid);
                    837:        else {
                    838:                if (s->cx <= sx - 1)
                    839:                        grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
                    840:                grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
                    841:        }
1.1       nicm      842:
1.17      nicm      843:        tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1       nicm      844: }
                    845:
                    846: /* Clear to start of screen. */
                    847: void
                    848: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
                    849: {
                    850:        struct screen   *s = ctx->s;
1.17      nicm      851:        struct tty_ctx   ttyctx;
1.1       nicm      852:        u_int            sx;
                    853:
1.31      nicm      854:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      855:
                    856:        sx = screen_size_x(s);
                    857:
                    858:        if (s->cy > 0)
1.4       nicm      859:                grid_view_clear(s->grid, 0, 0, sx, s->cy);
1.1       nicm      860:        if (s->cx > sx - 1)
                    861:                grid_view_clear(s->grid, 0, s->cy, sx, 1);
                    862:        else
1.4       nicm      863:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
1.1       nicm      864:
1.17      nicm      865:        tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1       nicm      866: }
                    867:
                    868: /* Clear entire screen. */
                    869: void
                    870: screen_write_clearscreen(struct screen_write_ctx *ctx)
                    871: {
                    872:        struct screen   *s = ctx->s;
1.17      nicm      873:        struct tty_ctx   ttyctx;
1.1       nicm      874:
1.31      nicm      875:        screen_write_initctx(ctx, &ttyctx, 0);
1.1       nicm      876:
1.46      nicm      877:        /* Scroll into history if it is enabled. */
                    878:        if (s->grid->flags & GRID_HISTORY)
                    879:                grid_view_clear_history(s->grid);
                    880:        else {
                    881:                grid_view_clear(
                    882:                    s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
                    883:        }
1.1       nicm      884:
1.17      nicm      885:        tty_write(tty_cmd_clearscreen, &ttyctx);
1.51      nicm      886: }
                    887:
                    888: /* Clear entire history. */
                    889: void
                    890: screen_write_clearhistory(struct screen_write_ctx *ctx)
                    891: {
                    892:        struct screen   *s = ctx->s;
                    893:        struct grid     *gd = s->grid;
                    894:
                    895:        grid_move_lines(gd, 0, gd->hsize, gd->sy);
                    896:        gd->hsize = 0;
1.1       nicm      897: }
                    898:
                    899: /* Write cell data. */
                    900: void
1.60      nicm      901: screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1.1       nicm      902: {
                    903:        struct screen           *s = ctx->s;
                    904:        struct grid             *gd = s->grid;
1.15      nicm      905:        struct tty_ctx           ttyctx;
1.64      nicm      906:        u_int                    width, xx, last;
1.33      nicm      907:        struct grid_cell         tmp_gc, *tmp_gcp;
1.60      nicm      908:        struct utf8_data         ud;
1.64      nicm      909:        int                      insert;
1.1       nicm      910:
                    911:        /* Ignore padding. */
                    912:        if (gc->flags & GRID_FLAG_PADDING)
                    913:                return;
1.60      nicm      914:        width = grid_cell_width(gc);
1.1       nicm      915:
1.32      nicm      916:        /*
                    917:         * If this is a wide character and there is no room on the screen, for
                    918:         * the entire character, don't print it.
                    919:         */
1.48      nicm      920:        if (!(s->mode & MODE_WRAP)
                    921:            && (width > 1 && (width > screen_size_x(s) ||
                    922:                (s->cx != screen_size_x(s)
                    923:                 && s->cx > screen_size_x(s) - width))))
1.32      nicm      924:                return;
                    925:
1.35      nicm      926:        /*
                    927:         * If the width is zero, combine onto the previous character, if
1.41      nicm      928:         * there is space.
1.35      nicm      929:         */
1.1       nicm      930:        if (width == 0) {
1.60      nicm      931:                grid_cell_get(gc, &ud);
                    932:                if (screen_write_combine(ctx, &ud) == 0) {
1.35      nicm      933:                        screen_write_initctx(ctx, &ttyctx, 0);
                    934:                        tty_write(tty_cmd_utf8character, &ttyctx);
1.1       nicm      935:                }
                    936:                return;
                    937:        }
                    938:
1.55      nicm      939:        /* Initialise the redraw context, saving the last cell. */
                    940:        screen_write_initctx(ctx, &ttyctx, 1);
                    941:
1.6       nicm      942:        /* If in insert mode, make space for the cells. */
1.55      nicm      943:        if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) {
1.6       nicm      944:                xx = screen_size_x(s) - s->cx - width;
                    945:                grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
                    946:                insert = 1;
1.64      nicm      947:        } else
                    948:                insert = 0;
1.6       nicm      949:
1.20      nicm      950:        /* Check this will fit on the current line and wrap if not. */
1.42      nicm      951:        if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
1.34      nicm      952:                screen_write_linefeed(ctx, 1);
1.30      nicm      953:                s->cx = 0;      /* carriage return */
1.1       nicm      954:        }
                    955:
1.64      nicm      956:        /* Sanity check cursor position. */
                    957:        if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1)
1.1       nicm      958:                return;
                    959:
                    960:        /* Handle overwriting of UTF-8 characters. */
1.43      nicm      961:        screen_write_overwrite(ctx, width);
1.1       nicm      962:
                    963:        /*
                    964:         * If the new character is UTF-8 wide, fill in padding cells. Have
                    965:         * already ensured there is enough room.
                    966:         */
                    967:        for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.18      nicm      968:                tmp_gcp = grid_view_get_cell(gd, xx, s->cy);
                    969:                if (tmp_gcp != NULL)
                    970:                        tmp_gcp->flags |= GRID_FLAG_PADDING;
1.1       nicm      971:        }
                    972:
                    973:        /* Set the cell. */
                    974:        grid_view_set_cell(gd, s->cx, s->cy, gc);
                    975:
1.64      nicm      976:        /*
                    977:         * Move the cursor. If not wrapping, stick at the last character and
                    978:         * replace it.
                    979:         */
1.65      nicm      980:        last = !(s->mode & MODE_WRAP);
1.64      nicm      981:        if (s->cx <= screen_size_x(s) - last - width)
                    982:                s->cx += width;
                    983:        else
                    984:                s->cx = screen_size_x(s) - last;
1.1       nicm      985:
                    986:        /* Draw to the screen if necessary. */
1.17      nicm      987:        if (insert) {
                    988:                ttyctx.num = width;
                    989:                tty_write(tty_cmd_insertcharacter, &ttyctx);
                    990:        }
1.1       nicm      991:        if (screen_check_selection(s, s->cx - width, s->cy)) {
1.33      nicm      992:                memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc);
1.60      nicm      993:                grid_cell_get(gc, &ud);
                    994:                grid_cell_set(&tmp_gc, &ud);
1.70      nicm      995:                tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET;
                    996:                tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET;
1.60      nicm      997:                tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
1.33      nicm      998:                tmp_gc.flags |= s->sel.cell.flags &
1.28      nicm      999:                    (GRID_FLAG_FG256|GRID_FLAG_BG256);
1.33      nicm     1000:                ttyctx.cell = &tmp_gc;
1.16      nicm     1001:                tty_write(tty_cmd_cell, &ttyctx);
1.15      nicm     1002:        } else {
                   1003:                ttyctx.cell = gc;
1.16      nicm     1004:                tty_write(tty_cmd_cell, &ttyctx);
1.15      nicm     1005:        }
1.35      nicm     1006: }
                   1007:
                   1008: /* Combine a UTF-8 zero-width character onto the previous. */
                   1009: int
1.60      nicm     1010: screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud)
1.35      nicm     1011: {
                   1012:        struct screen           *s = ctx->s;
                   1013:        struct grid             *gd = s->grid;
                   1014:        struct grid_cell        *gc;
1.60      nicm     1015:        struct utf8_data         ud1;
1.35      nicm     1016:
                   1017:        /* Can't combine if at 0. */
                   1018:        if (s->cx == 0)
                   1019:                return (-1);
                   1020:
1.60      nicm     1021:        /* Empty data is out. */
                   1022:        if (ud->size == 0)
1.37      nicm     1023:                fatalx("UTF-8 data empty");
                   1024:
1.60      nicm     1025:        /* Retrieve the previous cell. */
1.35      nicm     1026:        gc = grid_view_get_cell(gd, s->cx - 1, s->cy);
1.60      nicm     1027:        grid_cell_get(gc, &ud1);
1.35      nicm     1028:
1.60      nicm     1029:        /* Check there is enough space. */
                   1030:        if (ud1.size + ud->size > sizeof ud1.data)
                   1031:                return (-1);
1.35      nicm     1032:
1.60      nicm     1033:        /* Append the data and set the cell. */
                   1034:        memcpy(ud1.data + ud1.size, ud->data, ud->size);
                   1035:        ud1.size += ud->size;
                   1036:        grid_cell_set(gc, &ud1);
1.35      nicm     1037:
                   1038:        return (0);
1.1       nicm     1039: }
                   1040:
                   1041: /*
                   1042:  * UTF-8 wide characters are a bit of an annoyance. They take up more than one
                   1043:  * cell on the screen, so following cells must not be drawn by marking them as
                   1044:  * padding.
                   1045:  *
                   1046:  * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
                   1047:  * character, it is necessary to also overwrite any other cells which covered
                   1048:  * by the same character.
                   1049:  */
                   1050: void
1.43      nicm     1051: screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
1.1       nicm     1052: {
                   1053:        struct screen           *s = ctx->s;
                   1054:        struct grid             *gd = s->grid;
                   1055:        const struct grid_cell  *gc;
                   1056:        u_int                    xx;
                   1057:
                   1058:        gc = grid_view_peek_cell(gd, s->cx, s->cy);
                   1059:        if (gc->flags & GRID_FLAG_PADDING) {
                   1060:                /*
                   1061:                 * A padding cell, so clear any following and leading padding
                   1062:                 * cells back to the character. Don't overwrite the current
                   1063:                 * cell as that happens later anyway.
                   1064:                 */
                   1065:                xx = s->cx + 1;
                   1066:                while (--xx > 0) {
                   1067:                        gc = grid_view_peek_cell(gd, xx, s->cy);
                   1068:                        if (!(gc->flags & GRID_FLAG_PADDING))
                   1069:                                break;
                   1070:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
                   1071:                }
                   1072:
                   1073:                /* Overwrite the character at the start of this padding. */
                   1074:                grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1.43      nicm     1075:        }
1.1       nicm     1076:
1.43      nicm     1077:        /*
                   1078:         * Overwrite any padding cells that belong to a UTF-8 character
                   1079:         * we'll be overwriting with the current character.
                   1080:         */
                   1081:        xx = s->cx + width - 1;
                   1082:        while (++xx < screen_size_x(s)) {
                   1083:                gc = grid_view_peek_cell(gd, xx, s->cy);
                   1084:                if (!(gc->flags & GRID_FLAG_PADDING))
                   1085:                        break;
                   1086:                grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1.1       nicm     1087:        }
1.50      nicm     1088: }
                   1089:
                   1090: void
                   1091: screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
                   1092: {
                   1093:        struct tty_ctx  ttyctx;
                   1094:
                   1095:        screen_write_initctx(ctx, &ttyctx, 0);
                   1096:        ttyctx.ptr = str;
                   1097:        ttyctx.num = len;
                   1098:
                   1099:        tty_write(tty_cmd_setselection, &ttyctx);
1.47      nicm     1100: }
                   1101:
                   1102: void
                   1103: screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
                   1104: {
                   1105:        struct tty_ctx           ttyctx;
                   1106:
                   1107:        screen_write_initctx(ctx, &ttyctx, 0);
                   1108:        ttyctx.ptr = str;
                   1109:        ttyctx.num = len;
                   1110:
                   1111:        tty_write(tty_cmd_rawstring, &ttyctx);
1.1       nicm     1112: }