1219888Sed/*- 2257547Sray * Copyright (c) 2009, 2013 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8257547Sray * Portions of this software were developed by Oleksandr Rybalko 9257547Sray * under sponsorship from the FreeBSD Foundation. 10257547Sray * 11219888Sed * Redistribution and use in source and binary forms, with or without 12219888Sed * modification, are permitted provided that the following conditions 13219888Sed * are met: 14219888Sed * 1. Redistributions of source code must retain the above copyright 15219888Sed * notice, this list of conditions and the following disclaimer. 16219888Sed * 2. Redistributions in binary form must reproduce the above copyright 17219888Sed * notice, this list of conditions and the following disclaimer in the 18219888Sed * documentation and/or other materials provided with the distribution. 19219888Sed * 20219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30219888Sed * SUCH DAMAGE. 31219888Sed */ 32219888Sed 33219888Sed#include <sys/cdefs.h> 34219888Sed__FBSDID("$FreeBSD$"); 35219888Sed 36219888Sed#include <sys/param.h> 37219888Sed#include <sys/kernel.h> 38219888Sed#include <sys/lock.h> 39219888Sed#include <sys/malloc.h> 40219888Sed#include <sys/mutex.h> 41268037Smarius#include <sys/reboot.h> 42219888Sed#include <sys/systm.h> 43219888Sed 44219888Sed#include <dev/vt/vt.h> 45219888Sed 46219888Sedstatic MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 47219888Sed 48219888Sed#define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 49219888Sed#define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 50257971Sray 51258090Sray#define POS_INDEX(c, r) (((r) << 12) + (c)) 52258090Sray#define POS_COPY(d, s) do { \ 53258090Sray (d).tp_col = (s).tp_col; \ 54258090Sray (d).tp_row = (s).tp_row; \ 55258090Sray} while (0) 56257971Sray 57258090Sray 58256145Sray/* 59256145Sray * line4 60256145Sray * line5 <--- curroffset (terminal output to that line) 61256145Sray * line0 62256145Sray * line1 <--- roffset (history display from that point) 63256145Sray * line2 64256145Sray * line3 65256145Sray */ 66256145Srayint 67256145Srayvthistory_seek(struct vt_buf *vb, int offset, int whence) 68256145Sray{ 69257074Sray int diff, top, bottom, roffset; 70219888Sed 71256145Sray /* No scrolling if not enabled. */ 72256145Sray if ((vb->vb_flags & VBF_SCROLL) == 0) { 73256145Sray if (vb->vb_roffset != vb->vb_curroffset) { 74256145Sray vb->vb_roffset = vb->vb_curroffset; 75257074Sray return (0xffff); 76256145Sray } 77256145Sray return (0); /* No changes */ 78256145Sray } 79256970Sray 80271973Sdumbbell /* "top" may be a negative integer. */ 81271973Sdumbbell bottom = vb->vb_curroffset; 82271973Sdumbbell top = (vb->vb_flags & VBF_HISTORY_FULL) ? 83271973Sdumbbell bottom + vb->vb_scr_size.tp_row - vb->vb_history_size : 84271973Sdumbbell 0; 85271973Sdumbbell 86271973Sdumbbell roffset = 0; /* Make gcc happy. */ 87256145Sray switch (whence) { 88256145Sray case VHS_SET: 89271973Sdumbbell if (offset < 0) 90271973Sdumbbell offset = 0; 91271973Sdumbbell roffset = top + offset; 92256145Sray break; 93256145Sray case VHS_CUR: 94271973Sdumbbell /* 95271973Sdumbbell * Operate on copy of offset value, since it temporary 96271973Sdumbbell * can be bigger than amount of rows in buffer. 97271973Sdumbbell */ 98271973Sdumbbell roffset = vb->vb_roffset; 99271973Sdumbbell if (roffset >= bottom + vb->vb_scr_size.tp_row) 100271973Sdumbbell roffset -= vb->vb_history_size; 101271973Sdumbbell 102256145Sray roffset += offset; 103271973Sdumbbell roffset = MAX(roffset, top); 104271973Sdumbbell roffset = MIN(roffset, bottom); 105271973Sdumbbell 106271973Sdumbbell if (roffset < 0) 107271973Sdumbbell roffset = vb->vb_history_size + roffset; 108271973Sdumbbell 109256145Sray break; 110256145Sray case VHS_END: 111256145Sray /* Go to current offset. */ 112271973Sdumbbell roffset = vb->vb_curroffset; 113256145Sray break; 114256145Sray } 115256145Sray 116271973Sdumbbell diff = vb->vb_roffset != roffset; 117271973Sdumbbell vb->vb_roffset = roffset; 118256145Sray 119271973Sdumbbell return (diff); 120256145Sray} 121256145Sray 122256145Srayvoid 123256145Srayvthistory_addlines(struct vt_buf *vb, int offset) 124256145Sray{ 125256145Sray 126256145Sray vb->vb_curroffset += offset; 127256145Sray if (vb->vb_curroffset < 0) 128256145Sray vb->vb_curroffset = 0; 129271973Sdumbbell if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size) 130271973Sdumbbell vb->vb_flags |= VBF_HISTORY_FULL; 131256145Sray vb->vb_curroffset %= vb->vb_history_size; 132256145Sray if ((vb->vb_flags & VBF_SCROLL) == 0) { 133256145Sray vb->vb_roffset = vb->vb_curroffset; 134256145Sray } 135256145Sray} 136256145Sray 137256145Srayvoid 138256145Srayvthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 139256145Sray{ 140256145Sray 141256145Sray *offset = vb->vb_roffset; 142256145Sray} 143256145Sray 144262861Sjhb#ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 145258090Sray/* Translate current view row number to history row. */ 146258090Sraystatic int 147258090Srayvtbuf_wth(struct vt_buf *vb, int row) 148258090Sray{ 149258090Sray 150258090Sray return ((vb->vb_roffset + row) % vb->vb_history_size); 151258090Sray} 152262861Sjhb#endif 153258090Sray 154258090Sray/* Translate history row to current view row number. */ 155258090Sraystatic int 156271024Semastevtbuf_htw(const struct vt_buf *vb, int row) 157258090Sray{ 158258090Sray 159258090Sray /* 160258090Sray * total 1000 rows. 161258090Sray * History offset roffset winrow 162258090Sray * 205 200 ((205 - 200 + 1000) % 1000) = 5 163258090Sray * 90 990 ((90 - 990 + 1000) % 1000) = 100 164258090Sray */ 165258090Sray return ((row - vb->vb_roffset + vb->vb_history_size) % 166258090Sray vb->vb_history_size); 167258090Sray} 168258090Sray 169257971Srayint 170271024Semastevtbuf_iscursor(const struct vt_buf *vb, int row, int col) 171257971Sray{ 172258090Sray int sc, sr, ec, er, tmp; 173258090Sray 174258090Sray if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 175258090Sray (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 176257971Sray return (1); 177257971Sray 178258090Sray /* Mark cut/paste region. */ 179258090Sray 180258090Sray /* 181258090Sray * Luckily screen view is not like circular buffer, so we will 182258090Sray * calculate in screen coordinates. Translate first. 183258090Sray */ 184258090Sray sc = vb->vb_mark_start.tp_col; 185258090Sray sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 186258090Sray ec = vb->vb_mark_end.tp_col; 187258090Sray er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 188258090Sray 189258090Sray 190258090Sray /* Swap start and end if start > end. */ 191258090Sray if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 192258090Sray tmp = sc; sc = ec; ec = tmp; 193258090Sray tmp = sr; sr = er; er = tmp; 194258090Sray } 195258090Sray 196258090Sray if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 197258090Sray (POS_INDEX(col, row) < POS_INDEX(ec, er))) 198257971Sray return (1); 199257971Sray 200257971Sray return (0); 201257971Sray} 202257971Sray 203219888Sedstatic inline void 204270182Sdumbbellvtbuf_dirty_locked(struct vt_buf *vb, const term_rect_t *area) 205219888Sed{ 206219888Sed 207219888Sed if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 208219888Sed vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 209219888Sed if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 210219888Sed vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 211219888Sed if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 212219888Sed vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 213219888Sed if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 214219888Sed vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 215270182Sdumbbell} 216270182Sdumbbell 217271128Semastevoid 218270182Sdumbbellvtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 219270182Sdumbbell{ 220270182Sdumbbell 221270182Sdumbbell VTBUF_LOCK(vb); 222270182Sdumbbell vtbuf_dirty_locked(vb, area); 223219888Sed VTBUF_UNLOCK(vb); 224219888Sed} 225219888Sed 226219888Sedstatic inline void 227270182Sdumbbellvtbuf_dirty_cell_locked(struct vt_buf *vb, const term_pos_t *p) 228219888Sed{ 229219888Sed term_rect_t area; 230219888Sed 231219888Sed area.tr_begin = *p; 232219888Sed area.tr_end.tp_row = p->tp_row + 1; 233219888Sed area.tr_end.tp_col = p->tp_col + 1; 234270182Sdumbbell vtbuf_dirty_locked(vb, &area); 235219888Sed} 236219888Sed 237219888Sedstatic void 238219888Sedvtbuf_make_undirty(struct vt_buf *vb) 239219888Sed{ 240219888Sed 241256145Sray vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 242219888Sed vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 243219888Sed} 244219888Sed 245219888Sedvoid 246271973Sdumbbellvtbuf_undirty(struct vt_buf *vb, term_rect_t *r) 247219888Sed{ 248219888Sed 249219888Sed VTBUF_LOCK(vb); 250219888Sed *r = vb->vb_dirtyrect; 251219888Sed vtbuf_make_undirty(vb); 252219888Sed VTBUF_UNLOCK(vb); 253219888Sed} 254219888Sed 255219888Sedvoid 256219888Sedvtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 257219888Sed{ 258219888Sed const term_pos_t *p1 = &r->tr_begin; 259219888Sed term_rect_t area; 260219888Sed unsigned int rows, cols; 261256145Sray int pr, rdiff; 262219888Sed 263256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 264256145Sray ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 265256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 266256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 267256145Sray ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 268256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 269256145Sray 270256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 271256145Sray ("vtbuf_copy end.tp_row %d must be less than screen width %d", 272256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 273256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 274256145Sray ("vtbuf_copy end.tp_col %d must be less than screen height %d", 275256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 276256145Sray 277256145Sray KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 278256145Sray ("vtbuf_copy tp_row %d must be less than screen width %d", 279256145Sray p2->tp_row, vb->vb_scr_size.tp_row)); 280256145Sray KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 281256145Sray ("vtbuf_copy tp_col %d must be less than screen height %d", 282256145Sray p2->tp_col, vb->vb_scr_size.tp_col)); 283256145Sray 284219888Sed rows = r->tr_end.tp_row - r->tr_begin.tp_row; 285256145Sray rdiff = r->tr_begin.tp_row - p2->tp_row; 286219888Sed cols = r->tr_end.tp_col - r->tr_begin.tp_col; 287256145Sray if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 288256145Sray r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 289256145Sray (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 290271952Sray rdiff > 0) { /* Only forward direction. Do not eat history. */ 291256145Sray vthistory_addlines(vb, rdiff); 292256145Sray } else if (p2->tp_row < p1->tp_row) { 293256145Sray /* Handle overlapping copies of line segments. */ 294219888Sed /* Move data up. */ 295219888Sed for (pr = 0; pr < rows; pr++) 296219888Sed memmove( 297219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 298219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 299219888Sed cols * sizeof(term_char_t)); 300219888Sed } else { 301219888Sed /* Move data down. */ 302219888Sed for (pr = rows - 1; pr >= 0; pr--) 303219888Sed memmove( 304219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 305219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 306219888Sed cols * sizeof(term_char_t)); 307219888Sed } 308219888Sed 309219888Sed area.tr_begin = *p2; 310256145Sray area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 311256145Sray area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 312219888Sed vtbuf_dirty(vb, &area); 313219888Sed} 314219888Sed 315256145Sraystatic void 316219888Sedvtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 317219888Sed{ 318219888Sed unsigned int pr, pc; 319256145Sray term_char_t *row; 320219888Sed 321256145Sray for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 322256145Sray row = vb->vb_rows[(vb->vb_curroffset + pr) % 323256145Sray VTBUF_MAX_HEIGHT(vb)]; 324256145Sray for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 325256145Sray row[pc] = c; 326256145Sray } 327256145Sray } 328256145Sray} 329219888Sed 330256145Srayvoid 331256145Srayvtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 332256145Sray{ 333256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 334267538Sray ("vtbuf_fill_locked begin.tp_row %d must be < screen height %d", 335256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 336256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 337267538Sray ("vtbuf_fill_locked begin.tp_col %d must be < screen width %d", 338256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 339256145Sray 340256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 341267538Sray ("vtbuf_fill_locked end.tp_row %d must be <= screen height %d", 342256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 343256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 344267538Sray ("vtbuf_fill_locked end.tp_col %d must be <= screen width %d", 345256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 346256145Sray 347256145Sray VTBUF_LOCK(vb); 348256145Sray vtbuf_fill(vb, r, c); 349270182Sdumbbell vtbuf_dirty_locked(vb, r); 350256145Sray VTBUF_UNLOCK(vb); 351219888Sed} 352219888Sed 353256145Sraystatic void 354256145Srayvtbuf_init_rows(struct vt_buf *vb) 355256145Sray{ 356256145Sray int r; 357256145Sray 358256145Sray vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 359256145Sray 360256145Sray for (r = 0; r < vb->vb_history_size; r++) 361268037Smarius vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col]; 362256145Sray} 363256145Sray 364219888Sedvoid 365219888Sedvtbuf_init_early(struct vt_buf *vb) 366219888Sed{ 367268037Smarius term_rect_t rect; 368219888Sed 369219888Sed vb->vb_flags |= VBF_CURSOR; 370256145Sray vb->vb_roffset = 0; 371256145Sray vb->vb_curroffset = 0; 372258090Sray vb->vb_mark_start.tp_row = 0; 373258090Sray vb->vb_mark_start.tp_col = 0; 374258090Sray vb->vb_mark_end.tp_row = 0; 375258090Sray vb->vb_mark_end.tp_col = 0; 376256145Sray 377256145Sray vtbuf_init_rows(vb); 378268037Smarius rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0; 379271128Semaste rect.tr_end.tp_col = vb->vb_scr_size.tp_col; 380271128Semaste rect.tr_end.tp_row = vb->vb_history_size; 381271128Semaste vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 382219888Sed vtbuf_make_undirty(vb); 383256145Sray if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 384256145Sray mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 385256145Sray vb->vb_flags |= VBF_MTX_INIT; 386256145Sray } 387219888Sed} 388219888Sed 389219888Sedvoid 390219888Sedvtbuf_init(struct vt_buf *vb, const term_pos_t *p) 391219888Sed{ 392256145Sray int sz; 393219888Sed 394256145Sray vb->vb_scr_size = *p; 395256145Sray vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 396256145Sray 397256145Sray if ((vb->vb_flags & VBF_STATIC) == 0) { 398256145Sray sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 399256894Sray vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 400256145Sray 401256145Sray sz = vb->vb_history_size * sizeof(term_char_t *); 402256894Sray vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 403256145Sray } 404256145Sray 405219888Sed vtbuf_init_early(vb); 406219888Sed} 407219888Sed 408219888Sedvoid 409256145Srayvtbuf_sethistory_size(struct vt_buf *vb, int size) 410219888Sed{ 411256145Sray term_pos_t p; 412219888Sed 413256145Sray /* With same size */ 414256145Sray p.tp_row = vb->vb_scr_size.tp_row; 415256145Sray p.tp_col = vb->vb_scr_size.tp_col; 416256145Sray vtbuf_grow(vb, &p, size); 417256145Sray} 418256145Sray 419256145Srayvoid 420271128Semastevtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size) 421256145Sray{ 422271973Sdumbbell term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow; 423271973Sdumbbell int bufsize, rowssize, w, h, c, r, history_was_full; 424271973Sdumbbell unsigned int old_history_size; 425256145Sray term_rect_t rect; 426256145Sray 427256145Sray history_size = MAX(history_size, p->tp_row); 428256145Sray 429271973Sdumbbell /* Allocate new buffer. */ 430271973Sdumbbell bufsize = history_size * p->tp_col * sizeof(term_char_t); 431271973Sdumbbell new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 432271973Sdumbbell rowssize = history_size * sizeof(term_pos_t *); 433271973Sdumbbell rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 434219888Sed 435271973Sdumbbell /* Toggle it. */ 436271973Sdumbbell VTBUF_LOCK(vb); 437271973Sdumbbell old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 438271973Sdumbbell oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 439271973Sdumbbell copyrows = vb->vb_rows; 440256145Sray 441271973Sdumbbell w = vb->vb_scr_size.tp_col; 442271973Sdumbbell h = vb->vb_scr_size.tp_row; 443271973Sdumbbell old_history_size = vb->vb_history_size; 444271973Sdumbbell history_was_full = vb->vb_flags & VBF_HISTORY_FULL; 445256145Sray 446271973Sdumbbell vb->vb_history_size = history_size; 447271973Sdumbbell vb->vb_buffer = new; 448271973Sdumbbell vb->vb_rows = rows; 449271973Sdumbbell vb->vb_flags &= ~VBF_STATIC; 450271973Sdumbbell vb->vb_scr_size = *p; 451271973Sdumbbell vtbuf_init_rows(vb); 452271973Sdumbbell 453271973Sdumbbell /* Copy history and fill extra space if needed. */ 454271973Sdumbbell if (history_size > old_history_size) { 455271973Sdumbbell /* 456271973Sdumbbell * Copy rows to the new buffer. The first row in the history 457271973Sdumbbell * is back to index 0, ie. the new buffer doesn't cycle. 458271973Sdumbbell * 459271973Sdumbbell * The rest of the new buffer is initialized with blank 460271973Sdumbbell * content. 461271973Sdumbbell */ 462271973Sdumbbell for (r = 0; r < old_history_size; r ++) { 463271973Sdumbbell row = rows[r]; 464271973Sdumbbell 465271973Sdumbbell /* Compute the corresponding row in the old buffer. */ 466271973Sdumbbell if (history_was_full) 467271973Sdumbbell /* 468271973Sdumbbell * The buffer is full, the "top" row is 469271973Sdumbbell * the one just after the viewable area 470271973Sdumbbell * (curroffset + viewable height) in the 471271973Sdumbbell * cycling buffer. The corresponding row 472271973Sdumbbell * is computed from this top row. 473271973Sdumbbell */ 474271973Sdumbbell oldrow = copyrows[ 475271973Sdumbbell (vb->vb_curroffset + h + r) % 476271973Sdumbbell old_history_size]; 477271973Sdumbbell else 478271973Sdumbbell /* 479271973Sdumbbell * The buffer is not full, therefore, 480271973Sdumbbell * we didn't cycle already. The 481271973Sdumbbell * corresponding rows are the same in 482271973Sdumbbell * both buffers. 483271973Sdumbbell */ 484271973Sdumbbell oldrow = copyrows[r]; 485271973Sdumbbell 486271973Sdumbbell memmove(row, oldrow, 487271973Sdumbbell MIN(p->tp_col, w) * sizeof(term_char_t)); 488271973Sdumbbell 489271973Sdumbbell /* 490271973Sdumbbell * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 491271973Sdumbbell * extended lines of kernel text using the wrong 492271973Sdumbbell * background color. 493271973Sdumbbell */ 494271973Sdumbbell for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 495271973Sdumbbell row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR); 496271973Sdumbbell } 497271973Sdumbbell } 498271973Sdumbbell 499271973Sdumbbell /* Fill remaining rows. */ 500271973Sdumbbell rect.tr_begin.tp_col = 0; 501271973Sdumbbell rect.tr_begin.tp_row = old_history_size; 502271973Sdumbbell rect.tr_end.tp_col = p->tp_col; 503271973Sdumbbell rect.tr_end.tp_row = p->tp_row; 504271973Sdumbbell vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 505271973Sdumbbell 506271973Sdumbbell vb->vb_flags &= ~VBF_HISTORY_FULL; 507271973Sdumbbell } else { 508271973Sdumbbell /* 509271973Sdumbbell * Copy rows to the new buffer. The first row in the history 510271973Sdumbbell * is back to index 0, ie. the new buffer doesn't cycle. 511271973Sdumbbell * 512271973Sdumbbell * (old_history_size - history_size) lines of history are 513271973Sdumbbell * dropped. 514271973Sdumbbell */ 515256145Sray for (r = 0; r < history_size; r ++) { 516271973Sdumbbell row = rows[r]; 517271973Sdumbbell 518268037Smarius /* 519271973Sdumbbell * Compute the corresponding row in the old buffer. 520271973Sdumbbell * 521271973Sdumbbell * See the equivalent if{} block above for an 522271973Sdumbbell * explanation. 523271973Sdumbbell */ 524271973Sdumbbell if (history_was_full) 525271973Sdumbbell oldrow = copyrows[ 526271973Sdumbbell (vb->vb_curroffset + h + r + 527271973Sdumbbell (old_history_size - history_size)) % 528271973Sdumbbell old_history_size]; 529271973Sdumbbell else 530271973Sdumbbell oldrow = copyrows[ 531271973Sdumbbell (r + (old_history_size - history_size)) % 532271973Sdumbbell old_history_size]; 533271973Sdumbbell 534271973Sdumbbell memmove(row, oldrow, 535271973Sdumbbell MIN(p->tp_col, w) * sizeof(term_char_t)); 536271973Sdumbbell 537271973Sdumbbell /* 538268037Smarius * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 539268037Smarius * extended lines of kernel text using the wrong 540268037Smarius * background color. 541268037Smarius */ 542271973Sdumbbell for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 543271973Sdumbbell row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR); 544256145Sray } 545256145Sray } 546271973Sdumbbell 547271973Sdumbbell if (!history_was_full && 548271973Sdumbbell (vb->vb_curroffset + h) >= history_size) 549271973Sdumbbell vb->vb_flags |= VBF_HISTORY_FULL; 550219888Sed } 551271973Sdumbbell 552271973Sdumbbell /* 553271973Sdumbbell * If the screen is already filled (there are non-visible lines 554271973Sdumbbell * above the current viewable area), adjust curroffset to the 555271973Sdumbbell * new viewable area. 556271973Sdumbbell */ 557271973Sdumbbell if (!history_was_full && vb->vb_curroffset > 0) { 558271973Sdumbbell vb->vb_curroffset = vb->vb_curroffset + h - p->tp_row; 559271973Sdumbbell if (vb->vb_curroffset < 0) 560271973Sdumbbell vb->vb_curroffset += vb->vb_history_size; 561271973Sdumbbell vb->vb_curroffset %= vb->vb_history_size; 562271973Sdumbbell vb->vb_roffset = vb->vb_curroffset; 563271973Sdumbbell } 564271973Sdumbbell 565271973Sdumbbell vtbuf_make_undirty(vb); 566271973Sdumbbell VTBUF_UNLOCK(vb); 567271973Sdumbbell 568271973Sdumbbell /* Deallocate old buffer. */ 569271973Sdumbbell free(old, M_VTBUF); 570271973Sdumbbell free(oldrows, M_VTBUF); 571219888Sed} 572219888Sed 573219888Sedvoid 574219888Sedvtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 575219888Sed{ 576256145Sray term_char_t *row; 577219888Sed 578256145Sray KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 579256145Sray ("vtbuf_putchar tp_row %d must be less than screen width %d", 580256145Sray p->tp_row, vb->vb_scr_size.tp_row)); 581256145Sray KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 582256145Sray ("vtbuf_putchar tp_col %d must be less than screen height %d", 583256145Sray p->tp_col, vb->vb_scr_size.tp_col)); 584256145Sray 585256145Sray row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 586256145Sray VTBUF_MAX_HEIGHT(vb)]; 587256145Sray if (row[p->tp_col] != c) { 588256145Sray VTBUF_LOCK(vb); 589256145Sray row[p->tp_col] = c; 590270182Sdumbbell vtbuf_dirty_cell_locked(vb, p); 591256145Sray VTBUF_UNLOCK(vb); 592219888Sed } 593219888Sed} 594219888Sed 595219888Sedvoid 596219888Sedvtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 597219888Sed{ 598219888Sed 599219888Sed if (vb->vb_flags & VBF_CURSOR) { 600270182Sdumbbell VTBUF_LOCK(vb); 601270182Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 602219888Sed vb->vb_cursor = *p; 603270182Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 604270182Sdumbbell VTBUF_UNLOCK(vb); 605219888Sed } else { 606219888Sed vb->vb_cursor = *p; 607219888Sed } 608219888Sed} 609219888Sed 610262861Sjhb#ifndef SC_NO_CUTPASTE 611258090Sraystatic void 612258090Srayvtbuf_flush_mark(struct vt_buf *vb) 613258090Sray{ 614258090Sray term_rect_t area; 615258090Sray int s, e; 616258090Sray 617258090Sray /* Notify renderer to update marked region. */ 618258090Sray if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 619258090Sray vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 620258090Sray 621258090Sray s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 622258090Sray e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 623258090Sray 624258090Sray area.tr_begin.tp_col = 0; 625258090Sray area.tr_begin.tp_row = MIN(s, e); 626258090Sray 627258090Sray area.tr_end.tp_col = vb->vb_scr_size.tp_col; 628258090Sray area.tr_end.tp_row = MAX(s, e) + 1; 629258090Sray 630258090Sray vtbuf_dirty(vb, &area); 631258090Sray } 632258090Sray} 633258090Sray 634258090Srayint 635258090Srayvtbuf_get_marked_len(struct vt_buf *vb) 636258090Sray{ 637258090Sray int ei, si, sz; 638258090Sray term_pos_t s, e; 639258090Sray 640258090Sray /* Swap according to window coordinates. */ 641258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 642258134Sray vb->vb_mark_start.tp_col) > 643258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 644258134Sray vb->vb_mark_end.tp_col)) { 645258090Sray POS_COPY(e, vb->vb_mark_start); 646258090Sray POS_COPY(s, vb->vb_mark_end); 647258090Sray } else { 648258090Sray POS_COPY(s, vb->vb_mark_start); 649258090Sray POS_COPY(e, vb->vb_mark_end); 650258090Sray } 651258090Sray 652258090Sray si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 653258090Sray ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 654258090Sray 655258090Sray /* Number symbols and number of rows to inject \n */ 656271952Sray sz = ei - si + ((e.tp_row - s.tp_row) * 2); 657258090Sray 658258090Sray return (sz * sizeof(term_char_t)); 659258090Sray} 660258090Sray 661257971Srayvoid 662258090Srayvtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 663258090Sray{ 664258090Sray int i, r, c, cs, ce; 665258090Sray term_pos_t s, e; 666258090Sray 667258090Sray /* Swap according to window coordinates. */ 668258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 669258134Sray vb->vb_mark_start.tp_col) > 670258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 671258134Sray vb->vb_mark_end.tp_col)) { 672258090Sray POS_COPY(e, vb->vb_mark_start); 673258090Sray POS_COPY(s, vb->vb_mark_end); 674258090Sray } else { 675258090Sray POS_COPY(s, vb->vb_mark_start); 676258090Sray POS_COPY(e, vb->vb_mark_end); 677258090Sray } 678258090Sray 679258090Sray i = 0; 680258090Sray for (r = s.tp_row; r <= e.tp_row; r ++) { 681258090Sray cs = (r == s.tp_row)?s.tp_col:0; 682258090Sray ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 683258090Sray for (c = cs; c < ce; c ++) { 684258090Sray buf[i++] = vb->vb_rows[r][c]; 685258090Sray } 686258093Sray /* Add new line for all rows, but not for last one. */ 687258093Sray if (r != e.tp_row) { 688258093Sray buf[i++] = '\r'; 689258093Sray buf[i++] = '\n'; 690258093Sray } 691258090Sray } 692258090Sray} 693258090Sray 694258090Srayint 695257971Srayvtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 696257971Sray{ 697258136Sray term_char_t *r; 698258136Sray int i; 699257971Sray 700257971Sray switch (type) { 701258130Sray case VTB_MARK_END: /* B1 UP */ 702258130Sray if (vb->vb_mark_last != VTB_MARK_MOVE) 703258130Sray return (0); 704258130Sray /* FALLTHROUGH */ 705258130Sray case VTB_MARK_MOVE: 706257971Sray case VTB_MARK_EXTEND: 707258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 708257971Sray vb->vb_mark_end.tp_col = col; 709258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 710257971Sray break; 711257971Sray case VTB_MARK_START: 712258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 713257971Sray vb->vb_mark_start.tp_col = col; 714258090Sray vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 715257971Sray /* Start again, so clear end point. */ 716258090Sray vb->vb_mark_end.tp_col = col; 717258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 718257971Sray break; 719257971Sray case VTB_MARK_WORD: 720258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 721258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 722258090Sray vtbuf_wth(vb, row); 723258136Sray r = vb->vb_rows[vb->vb_mark_start.tp_row]; 724258136Sray for (i = col; i >= 0; i --) { 725258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 726258136Sray vb->vb_mark_start.tp_col = i + 1; 727258136Sray break; 728258136Sray } 729258136Sray } 730258136Sray for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 731258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 732258136Sray vb->vb_mark_end.tp_col = i; 733258136Sray break; 734258136Sray } 735258136Sray } 736258136Sray if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 737258136Sray vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 738257971Sray break; 739257971Sray case VTB_MARK_ROW: 740258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 741257971Sray vb->vb_mark_start.tp_col = 0; 742257971Sray vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 743258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 744258090Sray vtbuf_wth(vb, row); 745257971Sray break; 746258090Sray case VTB_MARK_NONE: 747258130Sray vb->vb_mark_last = type; 748258130Sray /* FALLTHROUGH */ 749258090Sray default: 750258090Sray /* panic? */ 751258090Sray return (0); 752257971Sray } 753258111Sray 754258130Sray vb->vb_mark_last = type; 755258111Sray /* Draw new marked region. */ 756258111Sray vtbuf_flush_mark(vb); 757258111Sray return (1); 758257971Sray} 759262861Sjhb#endif 760257971Sray 761257971Srayvoid 762219888Sedvtbuf_cursor_visibility(struct vt_buf *vb, int yes) 763219888Sed{ 764219888Sed int oflags, nflags; 765219888Sed 766219888Sed VTBUF_LOCK(vb); 767219888Sed oflags = vb->vb_flags; 768219888Sed if (yes) 769219888Sed vb->vb_flags |= VBF_CURSOR; 770219888Sed else 771219888Sed vb->vb_flags &= ~VBF_CURSOR; 772219888Sed nflags = vb->vb_flags; 773219888Sed 774219888Sed if (oflags != nflags) 775270182Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 776270182Sdumbbell VTBUF_UNLOCK(vb); 777219888Sed} 778258090Sray 779258090Srayvoid 780258090Srayvtbuf_scroll_mode(struct vt_buf *vb, int yes) 781258090Sray{ 782258090Sray int oflags, nflags; 783258090Sray 784258090Sray VTBUF_LOCK(vb); 785258090Sray oflags = vb->vb_flags; 786258090Sray if (yes) 787258090Sray vb->vb_flags |= VBF_SCROLL; 788258090Sray else 789258090Sray vb->vb_flags &= ~VBF_SCROLL; 790258090Sray nflags = vb->vb_flags; 791258090Sray 792258090Sray if (oflags != nflags) 793270182Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 794270182Sdumbbell VTBUF_UNLOCK(vb); 795258090Sray} 796258090Sray 797