vt_buf.c revision 270785
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: head/sys/dev/vt/vt_buf.c 270785 2014-08-29 08:16:31Z dumbbell $"); 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> 41267978Smarius#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 top = (vb->vb_flags & VBF_HISTORY_FULL)? 80256970Sray (vb->vb_curroffset + vb->vb_scr_size.tp_row):vb->vb_history_size; 81256970Sray bottom = vb->vb_curroffset + vb->vb_history_size; 82256970Sray 83256145Sray /* 84256145Sray * Operate on copy of offset value, since it temporary can be bigger 85256145Sray * than amount of rows in buffer. 86256145Sray */ 87256970Sray roffset = vb->vb_roffset + vb->vb_history_size; 88256145Sray switch (whence) { 89256145Sray case VHS_SET: 90257074Sray roffset = offset + vb->vb_history_size; 91256145Sray break; 92256145Sray case VHS_CUR: 93256145Sray roffset += offset; 94256145Sray break; 95256145Sray case VHS_END: 96256145Sray /* Go to current offset. */ 97257074Sray roffset = vb->vb_curroffset + vb->vb_history_size; 98256145Sray break; 99256145Sray } 100256145Sray 101256970Sray roffset = (roffset < top)?top:roffset; 102256970Sray roffset = (roffset > bottom)?bottom:roffset; 103256145Sray 104256970Sray roffset %= vb->vb_history_size; 105256970Sray 106256145Sray if (vb->vb_roffset != roffset) { 107257074Sray diff = vb->vb_roffset - roffset; 108256145Sray vb->vb_roffset = roffset; 109257074Sray /* 110257074Sray * Offset changed, please update Nth lines on sceen. 111257074Sray * +N - Nth lines at top; 112257074Sray * -N - Nth lines at bottom. 113257074Sray */ 114257074Sray return (diff); 115256145Sray } 116256145Sray return (0); /* No changes */ 117256145Sray} 118256145Sray 119256145Srayvoid 120256145Srayvthistory_addlines(struct vt_buf *vb, int offset) 121256145Sray{ 122256145Sray 123256145Sray vb->vb_curroffset += offset; 124256145Sray if (vb->vb_curroffset < 0) 125256145Sray vb->vb_curroffset = 0; 126256145Sray vb->vb_curroffset %= vb->vb_history_size; 127256145Sray if ((vb->vb_flags & VBF_SCROLL) == 0) { 128256145Sray vb->vb_roffset = vb->vb_curroffset; 129256145Sray } 130256145Sray} 131256145Sray 132256145Srayvoid 133256145Srayvthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 134256145Sray{ 135256145Sray 136256145Sray *offset = vb->vb_roffset; 137256145Sray} 138256145Sray 139259129Sray#ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 140258090Sray/* Translate current view row number to history row. */ 141258090Sraystatic int 142258090Srayvtbuf_wth(struct vt_buf *vb, int row) 143258090Sray{ 144258090Sray 145258090Sray return ((vb->vb_roffset + row) % vb->vb_history_size); 146258090Sray} 147259129Sray#endif 148258090Sray 149258090Sray/* Translate history row to current view row number. */ 150258090Sraystatic int 151270288Sdumbbellvtbuf_htw(const struct vt_buf *vb, int row) 152258090Sray{ 153258090Sray 154258090Sray /* 155258090Sray * total 1000 rows. 156258090Sray * History offset roffset winrow 157258090Sray * 205 200 ((205 - 200 + 1000) % 1000) = 5 158258090Sray * 90 990 ((90 - 990 + 1000) % 1000) = 100 159258090Sray */ 160258090Sray return ((row - vb->vb_roffset + vb->vb_history_size) % 161258090Sray vb->vb_history_size); 162258090Sray} 163258090Sray 164257971Srayint 165270288Sdumbbellvtbuf_iscursor(const struct vt_buf *vb, int row, int col) 166257971Sray{ 167258090Sray int sc, sr, ec, er, tmp; 168258090Sray 169258090Sray if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 170258090Sray (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 171257971Sray return (1); 172257971Sray 173258090Sray /* Mark cut/paste region. */ 174258090Sray 175258090Sray /* 176258090Sray * Luckily screen view is not like circular buffer, so we will 177258090Sray * calculate in screen coordinates. Translate first. 178258090Sray */ 179258090Sray sc = vb->vb_mark_start.tp_col; 180258090Sray sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 181258090Sray ec = vb->vb_mark_end.tp_col; 182258090Sray er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 183258090Sray 184258090Sray 185258090Sray /* Swap start and end if start > end. */ 186258090Sray if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 187258090Sray tmp = sc; sc = ec; ec = tmp; 188258090Sray tmp = sr; sr = er; er = tmp; 189258090Sray } 190258090Sray 191258090Sray if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 192258090Sray (POS_INDEX(col, row) < POS_INDEX(ec, er))) 193257971Sray return (1); 194257971Sray 195257971Sray return (0); 196257971Sray} 197257971Sray 198219888Sedstatic inline uint64_t 199219888Sedvtbuf_dirty_axis(unsigned int begin, unsigned int end) 200219888Sed{ 201219888Sed uint64_t left, right, mask; 202219888Sed 203219888Sed /* 204219888Sed * Mark all bits between begin % 64 and end % 64 dirty. 205219888Sed * This code is functionally equivalent to: 206219888Sed * 207219888Sed * for (i = begin; i < end; i++) 208219888Sed * mask |= (uint64_t)1 << (i % 64); 209219888Sed */ 210219888Sed 211219888Sed /* Obvious case. Mark everything dirty. */ 212219888Sed if (end - begin >= 64) 213219888Sed return (VBM_DIRTY); 214219888Sed 215219888Sed /* 1....0; used bits on the left. */ 216219888Sed left = VBM_DIRTY << begin % 64; 217219888Sed /* 0....1; used bits on the right. */ 218219888Sed right = VBM_DIRTY >> -end % 64; 219219888Sed 220219888Sed /* 221219888Sed * Only take the intersection. If the result of that is 0, it 222219888Sed * means that the selection crossed a 64 bit boundary along the 223219888Sed * way, which means we have to take the complement. 224219888Sed */ 225219888Sed mask = left & right; 226219888Sed if (mask == 0) 227219888Sed mask = left | right; 228219888Sed return (mask); 229219888Sed} 230219888Sed 231219888Sedstatic inline void 232269780Sdumbbellvtbuf_dirty_locked(struct vt_buf *vb, const term_rect_t *area) 233219888Sed{ 234219888Sed 235219888Sed if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 236219888Sed vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 237219888Sed if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 238219888Sed vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 239219888Sed if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 240219888Sed vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 241219888Sed if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 242219888Sed vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 243219888Sed vb->vb_dirtymask.vbm_row |= 244219888Sed vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row); 245219888Sed vb->vb_dirtymask.vbm_col |= 246219888Sed vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col); 247269780Sdumbbell} 248269780Sdumbbell 249270342Sdumbbellvoid 250269780Sdumbbellvtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 251269780Sdumbbell{ 252269780Sdumbbell 253269780Sdumbbell VTBUF_LOCK(vb); 254269780Sdumbbell vtbuf_dirty_locked(vb, area); 255219888Sed VTBUF_UNLOCK(vb); 256219888Sed} 257219888Sed 258219888Sedstatic inline void 259269780Sdumbbellvtbuf_dirty_cell_locked(struct vt_buf *vb, const term_pos_t *p) 260219888Sed{ 261219888Sed term_rect_t area; 262219888Sed 263219888Sed area.tr_begin = *p; 264219888Sed area.tr_end.tp_row = p->tp_row + 1; 265219888Sed area.tr_end.tp_col = p->tp_col + 1; 266269780Sdumbbell vtbuf_dirty_locked(vb, &area); 267219888Sed} 268219888Sed 269219888Sedstatic void 270219888Sedvtbuf_make_undirty(struct vt_buf *vb) 271219888Sed{ 272219888Sed 273256145Sray vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 274219888Sed vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 275219888Sed vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0; 276219888Sed} 277219888Sed 278219888Sedvoid 279219888Sedvtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m) 280219888Sed{ 281219888Sed 282219888Sed VTBUF_LOCK(vb); 283219888Sed *r = vb->vb_dirtyrect; 284219888Sed *m = vb->vb_dirtymask; 285219888Sed vtbuf_make_undirty(vb); 286219888Sed VTBUF_UNLOCK(vb); 287219888Sed} 288219888Sed 289219888Sedvoid 290219888Sedvtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 291219888Sed{ 292219888Sed const term_pos_t *p1 = &r->tr_begin; 293219888Sed term_rect_t area; 294219888Sed unsigned int rows, cols; 295256145Sray int pr, rdiff; 296219888Sed 297256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 298256145Sray ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 299256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 300256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 301256145Sray ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 302256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 303256145Sray 304256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 305256145Sray ("vtbuf_copy end.tp_row %d must be less than screen width %d", 306256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 307256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 308256145Sray ("vtbuf_copy end.tp_col %d must be less than screen height %d", 309256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 310256145Sray 311256145Sray KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 312256145Sray ("vtbuf_copy tp_row %d must be less than screen width %d", 313256145Sray p2->tp_row, vb->vb_scr_size.tp_row)); 314256145Sray KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 315256145Sray ("vtbuf_copy tp_col %d must be less than screen height %d", 316256145Sray p2->tp_col, vb->vb_scr_size.tp_col)); 317256145Sray 318219888Sed rows = r->tr_end.tp_row - r->tr_begin.tp_row; 319256145Sray rdiff = r->tr_begin.tp_row - p2->tp_row; 320219888Sed cols = r->tr_end.tp_col - r->tr_begin.tp_col; 321256145Sray if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 322256145Sray r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 323256145Sray (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 324256145Sray rdiff > 0) { /* Only forward dirrection. Do not eat history. */ 325256145Sray vthistory_addlines(vb, rdiff); 326256145Sray } else if (p2->tp_row < p1->tp_row) { 327256145Sray /* Handle overlapping copies of line segments. */ 328219888Sed /* Move data up. */ 329219888Sed for (pr = 0; pr < rows; pr++) 330219888Sed memmove( 331219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 332219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 333219888Sed cols * sizeof(term_char_t)); 334219888Sed } else { 335219888Sed /* Move data down. */ 336219888Sed for (pr = rows - 1; pr >= 0; pr--) 337219888Sed memmove( 338219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 339219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 340219888Sed cols * sizeof(term_char_t)); 341219888Sed } 342219888Sed 343219888Sed area.tr_begin = *p2; 344256145Sray area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 345256145Sray area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 346219888Sed vtbuf_dirty(vb, &area); 347219888Sed} 348219888Sed 349256145Sraystatic void 350219888Sedvtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 351219888Sed{ 352219888Sed unsigned int pr, pc; 353256145Sray term_char_t *row; 354219888Sed 355256145Sray for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 356256145Sray row = vb->vb_rows[(vb->vb_curroffset + pr) % 357256145Sray VTBUF_MAX_HEIGHT(vb)]; 358256145Sray for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 359256145Sray row[pc] = c; 360256145Sray } 361256145Sray } 362256145Sray} 363219888Sed 364256145Srayvoid 365256145Srayvtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 366256145Sray{ 367256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 368266856Semaste ("vtbuf_fill_locked begin.tp_row %d must be < screen height %d", 369256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 370256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 371266856Semaste ("vtbuf_fill_locked begin.tp_col %d must be < screen width %d", 372256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 373256145Sray 374256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 375266856Semaste ("vtbuf_fill_locked end.tp_row %d must be <= screen height %d", 376256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 377256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 378266856Semaste ("vtbuf_fill_locked end.tp_col %d must be <= screen width %d", 379256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 380256145Sray 381256145Sray VTBUF_LOCK(vb); 382256145Sray vtbuf_fill(vb, r, c); 383269780Sdumbbell vtbuf_dirty_locked(vb, r); 384256145Sray VTBUF_UNLOCK(vb); 385219888Sed} 386219888Sed 387256145Sraystatic void 388256145Srayvtbuf_init_rows(struct vt_buf *vb) 389256145Sray{ 390256145Sray int r; 391256145Sray 392256145Sray vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 393256145Sray 394256145Sray for (r = 0; r < vb->vb_history_size; r++) 395267978Smarius vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col]; 396256145Sray} 397256145Sray 398219888Sedvoid 399219888Sedvtbuf_init_early(struct vt_buf *vb) 400219888Sed{ 401267978Smarius term_rect_t rect; 402219888Sed 403219888Sed vb->vb_flags |= VBF_CURSOR; 404256145Sray vb->vb_roffset = 0; 405256145Sray vb->vb_curroffset = 0; 406258090Sray vb->vb_mark_start.tp_row = 0; 407258090Sray vb->vb_mark_start.tp_col = 0; 408258090Sray vb->vb_mark_end.tp_row = 0; 409258090Sray vb->vb_mark_end.tp_col = 0; 410256145Sray 411256145Sray vtbuf_init_rows(vb); 412267978Smarius rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0; 413270667Sdumbbell rect.tr_end.tp_col = vb->vb_scr_size.tp_col; 414270667Sdumbbell rect.tr_end.tp_row = vb->vb_history_size; 415270667Sdumbbell vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 416219888Sed vtbuf_make_undirty(vb); 417256145Sray if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 418256145Sray mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 419256145Sray vb->vb_flags |= VBF_MTX_INIT; 420256145Sray } 421219888Sed} 422219888Sed 423219888Sedvoid 424219888Sedvtbuf_init(struct vt_buf *vb, const term_pos_t *p) 425219888Sed{ 426256145Sray int sz; 427219888Sed 428256145Sray vb->vb_scr_size = *p; 429256145Sray vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 430256145Sray 431256145Sray if ((vb->vb_flags & VBF_STATIC) == 0) { 432256145Sray sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 433256894Sray vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 434256145Sray 435256145Sray sz = vb->vb_history_size * sizeof(term_char_t *); 436256894Sray vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 437256145Sray } 438256145Sray 439219888Sed vtbuf_init_early(vb); 440219888Sed} 441219888Sed 442219888Sedvoid 443256145Srayvtbuf_sethistory_size(struct vt_buf *vb, int size) 444219888Sed{ 445256145Sray term_pos_t p; 446219888Sed 447256145Sray /* With same size */ 448256145Sray p.tp_row = vb->vb_scr_size.tp_row; 449256145Sray p.tp_col = vb->vb_scr_size.tp_col; 450256145Sray vtbuf_grow(vb, &p, size); 451256145Sray} 452256145Sray 453256145Srayvoid 454270785Sdumbbellvtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size) 455256145Sray{ 456256145Sray term_char_t *old, *new, **rows, **oldrows, **copyrows, *row; 457256145Sray int bufsize, rowssize, w, h, c, r; 458256145Sray term_rect_t rect; 459256145Sray 460256145Sray history_size = MAX(history_size, p->tp_row); 461256145Sray 462265681Sray /* If new screen/history size bigger or buffer is VBF_STATIC. */ 463265681Sray if ((history_size > vb->vb_history_size) || (p->tp_col > 464265681Sray vb->vb_scr_size.tp_col) || (vb->vb_flags & VBF_STATIC)) { 465219888Sed /* Allocate new buffer. */ 466256145Sray bufsize = history_size * p->tp_col * sizeof(term_char_t); 467256894Sray new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 468256145Sray rowssize = history_size * sizeof(term_pos_t *); 469256894Sray rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 470219888Sed 471219888Sed /* Toggle it. */ 472219888Sed VTBUF_LOCK(vb); 473219888Sed old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 474256145Sray oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 475256145Sray copyrows = vb->vb_rows; 476256145Sray w = vb->vb_scr_size.tp_col; 477256145Sray h = vb->vb_history_size; 478256145Sray 479256145Sray vb->vb_history_size = history_size; 480219888Sed vb->vb_buffer = new; 481256145Sray vb->vb_rows = rows; 482219888Sed vb->vb_flags &= ~VBF_STATIC; 483256145Sray vb->vb_scr_size = *p; 484256145Sray vtbuf_init_rows(vb); 485256145Sray 486256145Sray /* Copy history and fill extra space. */ 487256145Sray for (r = 0; r < history_size; r ++) { 488267978Smarius /* 489267978Smarius * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 490267978Smarius * extended lines of kernel text using the wrong 491267978Smarius * background color. 492267978Smarius */ 493256145Sray row = rows[r]; 494256145Sray if (r < h) { /* Copy. */ 495256145Sray memmove(rows[r], copyrows[r], 496256145Sray MIN(p->tp_col, w) * sizeof(term_char_t)); 497256145Sray for (c = MIN(p->tp_col, w); c < p->tp_col; 498256145Sray c++) { 499267978Smarius row[c] = VTBUF_SPACE_CHAR( 500267978Smarius TERMINAL_NORM_ATTR); 501256145Sray } 502256145Sray } else { /* Just fill. */ 503256145Sray rect.tr_begin.tp_col = 0; 504256145Sray rect.tr_begin.tp_row = r; 505256145Sray rect.tr_end.tp_col = p->tp_col; 506256145Sray rect.tr_end.tp_row = p->tp_row; 507267978Smarius vtbuf_fill(vb, &rect, 508267978Smarius VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 509256145Sray break; 510256145Sray } 511256145Sray } 512219888Sed vtbuf_make_undirty(vb); 513219888Sed VTBUF_UNLOCK(vb); 514219888Sed /* Deallocate old buffer. */ 515256145Sray free(old, M_VTBUF); 516256145Sray free(oldrows, M_VTBUF); 517266861Semaste } else { 518266861Semaste /* Just update the size. */ 519266861Semaste vb->vb_scr_size = *p; 520219888Sed } 521219888Sed} 522219888Sed 523219888Sedvoid 524219888Sedvtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 525219888Sed{ 526256145Sray term_char_t *row; 527219888Sed 528256145Sray KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 529256145Sray ("vtbuf_putchar tp_row %d must be less than screen width %d", 530256145Sray p->tp_row, vb->vb_scr_size.tp_row)); 531256145Sray KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 532256145Sray ("vtbuf_putchar tp_col %d must be less than screen height %d", 533256145Sray p->tp_col, vb->vb_scr_size.tp_col)); 534256145Sray 535256145Sray row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 536256145Sray VTBUF_MAX_HEIGHT(vb)]; 537256145Sray if (row[p->tp_col] != c) { 538256145Sray VTBUF_LOCK(vb); 539256145Sray row[p->tp_col] = c; 540269780Sdumbbell vtbuf_dirty_cell_locked(vb, p); 541256145Sray VTBUF_UNLOCK(vb); 542219888Sed } 543219888Sed} 544219888Sed 545219888Sedvoid 546219888Sedvtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 547219888Sed{ 548219888Sed 549219888Sed if (vb->vb_flags & VBF_CURSOR) { 550269780Sdumbbell VTBUF_LOCK(vb); 551269780Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 552219888Sed vb->vb_cursor = *p; 553269780Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 554269780Sdumbbell VTBUF_UNLOCK(vb); 555219888Sed } else { 556219888Sed vb->vb_cursor = *p; 557219888Sed } 558219888Sed} 559219888Sed 560259129Sray#ifndef SC_NO_CUTPASTE 561258090Sraystatic void 562258090Srayvtbuf_flush_mark(struct vt_buf *vb) 563258090Sray{ 564258090Sray term_rect_t area; 565258090Sray int s, e; 566258090Sray 567258090Sray /* Notify renderer to update marked region. */ 568258090Sray if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 569258090Sray vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 570258090Sray 571258090Sray s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 572258090Sray e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 573258090Sray 574258090Sray area.tr_begin.tp_col = 0; 575258090Sray area.tr_begin.tp_row = MIN(s, e); 576258090Sray 577258090Sray area.tr_end.tp_col = vb->vb_scr_size.tp_col; 578258090Sray area.tr_end.tp_row = MAX(s, e) + 1; 579258090Sray 580258090Sray vtbuf_dirty(vb, &area); 581258090Sray } 582258090Sray} 583258090Sray 584258090Srayint 585258090Srayvtbuf_get_marked_len(struct vt_buf *vb) 586258090Sray{ 587258090Sray int ei, si, sz; 588258090Sray term_pos_t s, e; 589258090Sray 590258090Sray /* Swap according to window coordinates. */ 591258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 592258134Sray vb->vb_mark_start.tp_col) > 593258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 594258134Sray vb->vb_mark_end.tp_col)) { 595258090Sray POS_COPY(e, vb->vb_mark_start); 596258090Sray POS_COPY(s, vb->vb_mark_end); 597258090Sray } else { 598258090Sray POS_COPY(s, vb->vb_mark_start); 599258090Sray POS_COPY(e, vb->vb_mark_end); 600258090Sray } 601258090Sray 602258090Sray si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 603258090Sray ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 604258090Sray 605258090Sray /* Number symbols and number of rows to inject \n */ 606258090Sray sz = ei - si + ((e.tp_row - s.tp_row) * 2) + 1; 607258090Sray 608258090Sray return (sz * sizeof(term_char_t)); 609258090Sray} 610258090Sray 611257971Srayvoid 612258090Srayvtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 613258090Sray{ 614258090Sray int i, r, c, cs, ce; 615258090Sray term_pos_t s, e; 616258090Sray 617258090Sray /* Swap according to window coordinates. */ 618258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 619258134Sray vb->vb_mark_start.tp_col) > 620258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 621258134Sray vb->vb_mark_end.tp_col)) { 622258090Sray POS_COPY(e, vb->vb_mark_start); 623258090Sray POS_COPY(s, vb->vb_mark_end); 624258090Sray } else { 625258090Sray POS_COPY(s, vb->vb_mark_start); 626258090Sray POS_COPY(e, vb->vb_mark_end); 627258090Sray } 628258090Sray 629258090Sray i = 0; 630258090Sray for (r = s.tp_row; r <= e.tp_row; r ++) { 631258090Sray cs = (r == s.tp_row)?s.tp_col:0; 632258090Sray ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 633258090Sray for (c = cs; c < ce; c ++) { 634258090Sray buf[i++] = vb->vb_rows[r][c]; 635258090Sray } 636258093Sray /* Add new line for all rows, but not for last one. */ 637258093Sray if (r != e.tp_row) { 638258093Sray buf[i++] = '\r'; 639258093Sray buf[i++] = '\n'; 640258093Sray } 641258090Sray } 642258090Sray} 643258090Sray 644258090Srayint 645257971Srayvtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 646257971Sray{ 647258136Sray term_char_t *r; 648258136Sray int i; 649257971Sray 650257971Sray switch (type) { 651258130Sray case VTB_MARK_END: /* B1 UP */ 652258130Sray if (vb->vb_mark_last != VTB_MARK_MOVE) 653258130Sray return (0); 654258130Sray /* FALLTHROUGH */ 655258130Sray case VTB_MARK_MOVE: 656257971Sray case VTB_MARK_EXTEND: 657258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 658257971Sray vb->vb_mark_end.tp_col = col; 659258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 660257971Sray break; 661257971Sray case VTB_MARK_START: 662258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 663257971Sray vb->vb_mark_start.tp_col = col; 664258090Sray vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 665257971Sray /* Start again, so clear end point. */ 666258090Sray vb->vb_mark_end.tp_col = col; 667258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 668257971Sray break; 669257971Sray case VTB_MARK_WORD: 670258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 671258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 672258090Sray vtbuf_wth(vb, row); 673258136Sray r = vb->vb_rows[vb->vb_mark_start.tp_row]; 674258136Sray for (i = col; i >= 0; i --) { 675258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 676258136Sray vb->vb_mark_start.tp_col = i + 1; 677258136Sray break; 678258136Sray } 679258136Sray } 680258136Sray for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 681258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 682258136Sray vb->vb_mark_end.tp_col = i; 683258136Sray break; 684258136Sray } 685258136Sray } 686258136Sray if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 687258136Sray vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 688257971Sray break; 689257971Sray case VTB_MARK_ROW: 690258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 691257971Sray vb->vb_mark_start.tp_col = 0; 692257971Sray vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 693258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 694258090Sray vtbuf_wth(vb, row); 695257971Sray break; 696258090Sray case VTB_MARK_NONE: 697258130Sray vb->vb_mark_last = type; 698258130Sray /* FALLTHROUGH */ 699258090Sray default: 700258090Sray /* panic? */ 701258090Sray return (0); 702257971Sray } 703258111Sray 704258130Sray vb->vb_mark_last = type; 705258111Sray /* Draw new marked region. */ 706258111Sray vtbuf_flush_mark(vb); 707258111Sray return (1); 708257971Sray} 709259129Sray#endif 710257971Sray 711257971Srayvoid 712219888Sedvtbuf_cursor_visibility(struct vt_buf *vb, int yes) 713219888Sed{ 714219888Sed int oflags, nflags; 715219888Sed 716219888Sed VTBUF_LOCK(vb); 717219888Sed oflags = vb->vb_flags; 718219888Sed if (yes) 719219888Sed vb->vb_flags |= VBF_CURSOR; 720219888Sed else 721219888Sed vb->vb_flags &= ~VBF_CURSOR; 722219888Sed nflags = vb->vb_flags; 723219888Sed 724219888Sed if (oflags != nflags) 725269780Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 726269780Sdumbbell VTBUF_UNLOCK(vb); 727219888Sed} 728258090Sray 729258090Srayvoid 730258090Srayvtbuf_scroll_mode(struct vt_buf *vb, int yes) 731258090Sray{ 732258090Sray int oflags, nflags; 733258090Sray 734258090Sray VTBUF_LOCK(vb); 735258090Sray oflags = vb->vb_flags; 736258090Sray if (yes) 737258090Sray vb->vb_flags |= VBF_SCROLL; 738258090Sray else 739258090Sray vb->vb_flags &= ~VBF_SCROLL; 740258090Sray nflags = vb->vb_flags; 741258090Sray 742258090Sray if (oflags != nflags) 743269780Sdumbbell vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 744269780Sdumbbell VTBUF_UNLOCK(vb); 745258090Sray} 746258090Sray 747