The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vt/vt_buf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009, 2013 The FreeBSD Foundation
    5  *
    6  * This software was developed by Ed Schouten under sponsorship from the
    7  * FreeBSD Foundation.
    8  *
    9  * Portions of this software were developed by Oleksandr Rybalko
   10  * under sponsorship from the FreeBSD Foundation.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/lock.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mutex.h>
   43 #include <sys/reboot.h>
   44 
   45 #include <dev/vt/vt.h>
   46 
   47 static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer");
   48 
   49 #define VTBUF_LOCK(vb)          mtx_lock_spin(&(vb)->vb_lock)
   50 #define VTBUF_UNLOCK(vb)        mtx_unlock_spin(&(vb)->vb_lock)
   51 
   52 #define POS_INDEX(c, r) (((r) << 12) + (c))
   53 #define POS_COPY(d, s)  do {    \
   54         (d).tp_col = (s).tp_col;        \
   55         (d).tp_row = (s).tp_row;        \
   56 } while (0)
   57 
   58 #ifndef SC_NO_CUTPASTE
   59 static int vtbuf_htw(const struct vt_buf *vb, int row);
   60 static int vtbuf_wth(const struct vt_buf *vb, int row);
   61 static int vtbuf_in_this_range(int begin, int test, int end, int sz);
   62 #endif
   63 
   64 /*
   65  * line4
   66  * line5 <--- curroffset (terminal output to that line)
   67  * line0
   68  * line1                  <--- roffset (history display from that point)
   69  * line2
   70  * line3
   71  */
   72 int
   73 vthistory_seek(struct vt_buf *vb, int offset, int whence)
   74 {
   75         int diff, top, bottom, roffset;
   76 
   77         /* No scrolling if not enabled. */
   78         if ((vb->vb_flags & VBF_SCROLL) == 0) {
   79                 if (vb->vb_roffset != vb->vb_curroffset) {
   80                         vb->vb_roffset = vb->vb_curroffset;
   81                         return (0xffff);
   82                 }
   83                 return (0); /* No changes */
   84         }
   85 
   86         /* "top" may be a negative integer. */
   87         bottom = vb->vb_curroffset;
   88         top = (vb->vb_flags & VBF_HISTORY_FULL) ?
   89             bottom + vb->vb_scr_size.tp_row - vb->vb_history_size :
   90             0;
   91 
   92         roffset = 0; /* Make gcc happy. */
   93         switch (whence) {
   94         case VHS_SET:
   95                 if (offset < 0)
   96                         offset = 0;
   97                 roffset = top + offset;
   98                 break;
   99         case VHS_CUR:
  100                 /*
  101                  * Operate on copy of offset value, since it temporary
  102                  * can be bigger than amount of rows in buffer.
  103                  */
  104                 roffset = vb->vb_roffset;
  105                 if (roffset >= bottom + vb->vb_scr_size.tp_row)
  106                         roffset -= vb->vb_history_size;
  107 
  108                 roffset += offset;
  109                 roffset = MAX(roffset, top);
  110                 roffset = MIN(roffset, bottom);
  111 
  112                 if (roffset < 0)
  113                         roffset = vb->vb_history_size + roffset;
  114 
  115                 break;
  116         case VHS_END:
  117                 /* Go to current offset. */
  118                 roffset = vb->vb_curroffset;
  119                 break;
  120         }
  121 
  122         diff = vb->vb_roffset != roffset;
  123         vb->vb_roffset = roffset;
  124 
  125         return (diff);
  126 }
  127 
  128 void
  129 vthistory_addlines(struct vt_buf *vb, int offset)
  130 {
  131 #ifndef SC_NO_CUTPASTE
  132         int cur, sz;
  133 #endif
  134 
  135         vb->vb_curroffset += offset;
  136         if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size) {
  137                 vb->vb_flags |= VBF_HISTORY_FULL;
  138                 vb->vb_curroffset %= vb->vb_history_size;
  139         }
  140         if ((vb->vb_flags & VBF_SCROLL) == 0) {
  141                 vb->vb_roffset = vb->vb_curroffset;
  142         }
  143 
  144 #ifndef SC_NO_CUTPASTE
  145         sz = vb->vb_history_size;
  146         cur = vb->vb_roffset + vb->vb_scr_size.tp_row + sz - 1;
  147         if (vtbuf_in_this_range(cur, vb->vb_mark_start.tp_row, cur + offset, sz) ||
  148             vtbuf_in_this_range(cur, vb->vb_mark_end.tp_row, cur + offset, sz)) {
  149                 /* clear screen selection */
  150                 vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row;
  151                 vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col;
  152         }
  153 #endif
  154 }
  155 
  156 void
  157 vthistory_getpos(const struct vt_buf *vb, unsigned int *offset)
  158 {
  159 
  160         *offset = vb->vb_roffset;
  161 }
  162 
  163 #ifndef SC_NO_CUTPASTE  /* Only mouse support use it now. */
  164 /* Translate history row to current view row number. */
  165 static int
  166 vtbuf_htw(const struct vt_buf *vb, int row)
  167 {
  168 
  169         /*
  170          * total 1000 rows.
  171          * History offset       roffset winrow
  172          *      205             200     ((205 - 200 + 1000) % 1000) = 5
  173          *      90              990     ((90 - 990 + 1000) % 1000) = 100
  174          */
  175         return ((row - vb->vb_roffset + vb->vb_history_size) %
  176             vb->vb_history_size);
  177 }
  178 
  179 /* Translate current view row number to history row. */
  180 static int
  181 vtbuf_wth(const struct vt_buf *vb, int row)
  182 {
  183 
  184         return ((vb->vb_roffset + row) % vb->vb_history_size);
  185 }
  186 
  187 /*
  188  * Test if an index in a circular buffer is within a range.
  189  *
  190  * begin - start index
  191  * end - end index
  192  * test - test index
  193  * sz - size of circular buffer when it turns over
  194  */
  195 static int
  196 vtbuf_in_this_range(int begin, int test, int end, int sz)
  197 {
  198 
  199         begin %= sz;
  200         end %= sz;
  201 
  202         /* check for inversion */
  203         if (begin > end)
  204                 return (test >= begin || test < end);
  205         else
  206                 return (test >= begin && test < end);
  207 }
  208 #endif
  209 
  210 int
  211 vtbuf_iscursor(const struct vt_buf *vb, int row, int col)
  212 {
  213 #ifndef SC_NO_CUTPASTE
  214         int sc, sr, sz, ec, er, tmp;
  215 #endif
  216 
  217         if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR &&
  218             (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col))
  219                 return (1);
  220 
  221 #ifndef SC_NO_CUTPASTE
  222         /* Mark cut/paste region. */
  223         if (vb->vb_mark_start.tp_col == vb->vb_mark_end.tp_col &&
  224             vb->vb_mark_start.tp_row == vb->vb_mark_end.tp_row)
  225                 return (0);
  226 
  227         sc = vb->vb_mark_start.tp_col;
  228         sr = vb->vb_mark_start.tp_row;
  229         ec = vb->vb_mark_end.tp_col;
  230         er = vb->vb_mark_end.tp_row;
  231 
  232         /*
  233          * Information about if the selection was made bottom-top or
  234          * top-bottom is lost due to modulo arithmetics and needs to
  235          * be recovered:
  236          */
  237         sz = vb->vb_history_size;
  238         tmp = (sz + er - sr) % sz;
  239         row = vtbuf_wth(vb, row);
  240 
  241         /* Swap start and end if start > end */
  242         if ((2 * tmp) > sz || (tmp == 0 && sc > ec)) {
  243                 tmp = sc; sc = ec; ec = tmp;
  244                 tmp = sr; sr = er; er = tmp;
  245         }
  246 
  247         if (vtbuf_in_this_range(POS_INDEX(sc, sr), POS_INDEX(col, row),
  248             POS_INDEX(ec, er), POS_INDEX(0, sz)))
  249                 return (1);
  250 #endif
  251 
  252         return (0);
  253 }
  254 
  255 void
  256 vtbuf_lock(struct vt_buf *vb)
  257 {
  258 
  259         VTBUF_LOCK(vb);
  260 }
  261 
  262 void
  263 vtbuf_unlock(struct vt_buf *vb)
  264 {
  265 
  266         VTBUF_UNLOCK(vb);
  267 }
  268 
  269 void
  270 vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area)
  271 {
  272 
  273         if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row)
  274                 vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row;
  275         if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col)
  276                 vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col;
  277         if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row)
  278                 vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row;
  279         if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col)
  280                 vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col;
  281 }
  282 
  283 static inline void
  284 vtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p)
  285 {
  286         term_rect_t area;
  287 
  288         area.tr_begin = *p;
  289         area.tr_end.tp_row = p->tp_row + 1;
  290         area.tr_end.tp_col = p->tp_col + 1;
  291         vtbuf_dirty(vb, &area);
  292 }
  293 
  294 static void
  295 vtbuf_make_undirty(struct vt_buf *vb)
  296 {
  297 
  298         vb->vb_dirtyrect.tr_begin = vb->vb_scr_size;
  299         vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0;
  300 }
  301 
  302 void
  303 vtbuf_undirty(struct vt_buf *vb, term_rect_t *r)
  304 {
  305 
  306         *r = vb->vb_dirtyrect;
  307         vtbuf_make_undirty(vb);
  308 }
  309 
  310 void
  311 vtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2)
  312 {
  313         const term_pos_t *p1 = &r->tr_begin;
  314         term_rect_t area;
  315         unsigned int rows, cols;
  316         int pr, rdiff;
  317 
  318         KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row,
  319             ("vtbuf_copy begin.tp_row %d must be less than screen width %d",
  320                 r->tr_begin.tp_row, vb->vb_scr_size.tp_row));
  321         KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col,
  322             ("vtbuf_copy begin.tp_col %d must be less than screen height %d",
  323                 r->tr_begin.tp_col, vb->vb_scr_size.tp_col));
  324 
  325         KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row,
  326             ("vtbuf_copy end.tp_row %d must be less than screen width %d",
  327                 r->tr_end.tp_row, vb->vb_scr_size.tp_row));
  328         KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col,
  329             ("vtbuf_copy end.tp_col %d must be less than screen height %d",
  330                 r->tr_end.tp_col, vb->vb_scr_size.tp_col));
  331 
  332         KASSERT(p2->tp_row < vb->vb_scr_size.tp_row,
  333             ("vtbuf_copy tp_row %d must be less than screen width %d",
  334                 p2->tp_row, vb->vb_scr_size.tp_row));
  335         KASSERT(p2->tp_col < vb->vb_scr_size.tp_col,
  336             ("vtbuf_copy tp_col %d must be less than screen height %d",
  337                 p2->tp_col, vb->vb_scr_size.tp_col));
  338 
  339         rows = r->tr_end.tp_row - r->tr_begin.tp_row;
  340         rdiff = r->tr_begin.tp_row - p2->tp_row;
  341         cols = r->tr_end.tp_col - r->tr_begin.tp_col;
  342         if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 &&
  343             r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */
  344             (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */
  345             rdiff > 0) { /* Only forward direction. Do not eat history. */
  346                 vthistory_addlines(vb, rdiff);
  347         } else if (p2->tp_row < p1->tp_row) {
  348                 /* Handle overlapping copies of line segments. */
  349                 /* Move data up. */
  350                 for (pr = 0; pr < rows; pr++)
  351                         memmove(
  352                             &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col),
  353                             &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col),
  354                             cols * sizeof(term_char_t));
  355         } else {
  356                 /* Move data down. */
  357                 for (pr = rows - 1; pr >= 0; pr--)
  358                         memmove(
  359                             &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col),
  360                             &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col),
  361                             cols * sizeof(term_char_t));
  362         }
  363 
  364         area.tr_begin = *p2;
  365         area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row);
  366         area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col);
  367         vtbuf_dirty(vb, &area);
  368 }
  369 
  370 static void
  371 vtbuf_do_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c)
  372 {
  373         unsigned int pr, pc;
  374         term_char_t *row;
  375 
  376         for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) {
  377                 row = vb->vb_rows[(vb->vb_curroffset + pr) %
  378                     VTBUF_MAX_HEIGHT(vb)];
  379                 for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) {
  380                         row[pc] = c;
  381                 }
  382         }
  383 }
  384 
  385 void
  386 vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c)
  387 {
  388 
  389         KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row,
  390             ("vtbuf_fill begin.tp_row %d must be < screen height %d",
  391                 r->tr_begin.tp_row, vb->vb_scr_size.tp_row));
  392         KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col,
  393             ("vtbuf_fill begin.tp_col %d must be < screen width %d",
  394                 r->tr_begin.tp_col, vb->vb_scr_size.tp_col));
  395 
  396         KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row,
  397             ("vtbuf_fill end.tp_row %d must be <= screen height %d",
  398                 r->tr_end.tp_row, vb->vb_scr_size.tp_row));
  399         KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col,
  400             ("vtbuf_fill end.tp_col %d must be <= screen width %d",
  401                 r->tr_end.tp_col, vb->vb_scr_size.tp_col));
  402 
  403         vtbuf_do_fill(vb, r, c);
  404         vtbuf_dirty(vb, r);
  405 }
  406 
  407 static void
  408 vtbuf_init_rows(struct vt_buf *vb)
  409 {
  410         int r;
  411 
  412         vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row);
  413 
  414         for (r = 0; r < vb->vb_history_size; r++)
  415                 vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col];
  416 }
  417 
  418 static void
  419 vtbuf_do_clearhistory(struct vt_buf *vb)
  420 {
  421         term_rect_t rect;
  422         const teken_attr_t *a;
  423         term_char_t ch;
  424 
  425         a = teken_get_curattr(&vb->vb_terminal->tm_emulator);
  426         ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor);
  427 
  428         rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0;
  429         rect.tr_end.tp_col = vb->vb_scr_size.tp_col;
  430         rect.tr_end.tp_row = vb->vb_history_size;
  431 
  432         vtbuf_do_fill(vb, &rect, VTBUF_SPACE_CHAR(ch));
  433 }
  434 
  435 static void
  436 vtbuf_reset_scrollback(struct vt_buf *vb)
  437 {
  438         vb->vb_roffset = 0;
  439         vb->vb_curroffset = 0;
  440         vb->vb_mark_start.tp_row = 0;
  441         vb->vb_mark_start.tp_col = 0;
  442         vb->vb_mark_end.tp_row = 0;
  443         vb->vb_mark_end.tp_col = 0;
  444 }
  445 
  446 void
  447 vtbuf_init_early(struct vt_buf *vb)
  448 {
  449         vb->vb_flags |= VBF_CURSOR;
  450         vtbuf_reset_scrollback(vb);
  451         vtbuf_init_rows(vb);
  452         vtbuf_do_clearhistory(vb);
  453         vtbuf_make_undirty(vb);
  454         if ((vb->vb_flags & VBF_MTX_INIT) == 0) {
  455                 mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN);
  456                 vb->vb_flags |= VBF_MTX_INIT;
  457         }
  458 }
  459 
  460 void
  461 vtbuf_init(struct vt_buf *vb, const term_pos_t *p)
  462 {
  463         int sz;
  464 
  465         vb->vb_scr_size = *p;
  466         vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE;
  467 
  468         if ((vb->vb_flags & VBF_STATIC) == 0) {
  469                 sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t);
  470                 vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO);
  471 
  472                 sz = vb->vb_history_size * sizeof(term_char_t *);
  473                 vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO);
  474         }
  475 
  476         vtbuf_init_early(vb);
  477 }
  478 
  479 void
  480 vtbuf_clearhistory(struct vt_buf *vb)
  481 {
  482         VTBUF_LOCK(vb);
  483         vtbuf_do_clearhistory(vb);
  484         vtbuf_reset_scrollback(vb);
  485         vb->vb_flags &= ~VBF_HISTORY_FULL;
  486         VTBUF_UNLOCK(vb);
  487 }
  488 
  489 void
  490 vtbuf_sethistory_size(struct vt_buf *vb, unsigned int size)
  491 {
  492         term_pos_t p;
  493 
  494         /* With same size */
  495         p.tp_row = vb->vb_scr_size.tp_row;
  496         p.tp_col = vb->vb_scr_size.tp_col;
  497         vtbuf_grow(vb, &p, size);
  498 }
  499 
  500 void
  501 vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size)
  502 {
  503         term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow;
  504         unsigned int w, h, c, r, old_history_size;
  505         size_t bufsize, rowssize;
  506         int history_full;
  507         const teken_attr_t *a;
  508         term_char_t ch;
  509 
  510         a = teken_get_curattr(&vb->vb_terminal->tm_emulator);
  511         ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor);
  512 
  513         history_size = MAX(history_size, p->tp_row);
  514 
  515         /* Allocate new buffer. */
  516         bufsize = history_size * p->tp_col * sizeof(term_char_t);
  517         new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO);
  518         rowssize = history_size * sizeof(term_pos_t *);
  519         rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO);
  520 
  521         /* Toggle it. */
  522         VTBUF_LOCK(vb);
  523         old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
  524         oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
  525         copyrows = vb->vb_rows;
  526 
  527         w = vb->vb_scr_size.tp_col;
  528         h = vb->vb_scr_size.tp_row;
  529         old_history_size = vb->vb_history_size;
  530         history_full = vb->vb_flags & VBF_HISTORY_FULL ||
  531             vb->vb_curroffset + h >= history_size;
  532 
  533         vb->vb_history_size = history_size;
  534         vb->vb_buffer = new;
  535         vb->vb_rows = rows;
  536         vb->vb_flags &= ~VBF_STATIC;
  537         vb->vb_scr_size = *p;
  538         vtbuf_init_rows(vb);
  539 
  540         /*
  541          * Copy rows to the new buffer. The first row in the history
  542          * is back to index 0, ie. the new buffer doesn't cycle.
  543          */
  544         if (history_size > old_history_size) {
  545                 for (r = 0; r < old_history_size; r++) {
  546                         row = rows[r];
  547 
  548                         /* Compute the corresponding row in the old buffer. */
  549                         if (history_full)
  550                                 /*
  551                                  * The buffer is full, the "top" row is
  552                                  * the one just after the viewable area
  553                                  * (curroffset + viewable height) in the
  554                                  * cycling buffer. The corresponding row
  555                                  * is computed from this top row.
  556                                  */
  557                                 oldrow = copyrows[
  558                                     (vb->vb_curroffset + h + r) %
  559                                     old_history_size];
  560                         else
  561                                 /*
  562                                  * The buffer is not full, therefore,
  563                                  * we didn't cycle already. The
  564                                  * corresponding rows are the same in
  565                                  * both buffers.
  566                                  */
  567                                 oldrow = copyrows[r];
  568 
  569                         memmove(row, oldrow,
  570                             MIN(p->tp_col, w) * sizeof(term_char_t));
  571 
  572                         /*
  573                          * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
  574                          * extended lines of kernel text using the wrong
  575                          * background color.
  576                          */
  577                         for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
  578                                 row[c] = VTBUF_SPACE_CHAR(ch);
  579                         }
  580                 }
  581 
  582                 /* Fill remaining rows. */
  583                 for (r = old_history_size; r < history_size; r++) {
  584                         row = rows[r];
  585                         for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
  586                                 row[c] = VTBUF_SPACE_CHAR(ch);
  587                         }
  588                 }
  589 
  590                 vb->vb_flags &= ~VBF_HISTORY_FULL;
  591 
  592                 /*
  593                  * If the screen is already filled (there are non-visible lines
  594                  * above the current viewable area), adjust curroffset to the
  595                  * new viewable area.
  596                  *
  597                  * If the old buffer was full, set curroffset to the
  598                  * <h>th most recent line of history in the new, non-cycled
  599                  * buffer. Otherwise, it didn't cycle, so the old curroffset
  600                  * is the same in the new buffer.
  601                  */
  602                 if (history_full)
  603                         vb->vb_curroffset = old_history_size - h;
  604         } else {
  605                 /*
  606                  * (old_history_size - history_size) lines of history are
  607                  * dropped.
  608                  */
  609                 for (r = 0; r < history_size; r++) {
  610                         row = rows[r];
  611 
  612                         /*
  613                          * Compute the corresponding row in the old buffer.
  614                          *
  615                          * See the equivalent if{} block above for an
  616                          * explanation.
  617                          */
  618                         if (history_full)
  619                                 oldrow = copyrows[
  620                                     (vb->vb_curroffset + h + r +
  621                                      (old_history_size - history_size)) %
  622                                     old_history_size];
  623                         else
  624                                 oldrow = copyrows[r];
  625 
  626                         memmove(row, oldrow,
  627                             MIN(p->tp_col, w) * sizeof(term_char_t));
  628 
  629                         /*
  630                          * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
  631                          * extended lines of kernel text using the wrong
  632                          * background color.
  633                          */
  634                         for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
  635                                 row[c] = VTBUF_SPACE_CHAR(ch);
  636                         }
  637                 }
  638 
  639                 if (history_full) {
  640                         vb->vb_curroffset = history_size - h;
  641                         vb->vb_flags |= VBF_HISTORY_FULL;
  642                 }
  643         }
  644 
  645         vb->vb_roffset = vb->vb_curroffset;
  646 
  647         /* Adjust cursor position. */
  648         if (vb->vb_cursor.tp_col > p->tp_col - 1)
  649                 /*
  650                  * Move cursor to the last column, in case its previous
  651                  * position is outside of the new screen area.
  652                  */
  653                 vb->vb_cursor.tp_col = p->tp_col - 1;
  654 
  655         if (vb->vb_curroffset > 0 || vb->vb_cursor.tp_row > p->tp_row - 1)
  656                 /* Move cursor to the last line on the screen. */
  657                 vb->vb_cursor.tp_row = p->tp_row - 1;
  658 
  659         VTBUF_UNLOCK(vb);
  660 
  661         /* Deallocate old buffer. */
  662         free(old, M_VTBUF);
  663         free(oldrows, M_VTBUF);
  664 }
  665 
  666 void
  667 vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c)
  668 {
  669         term_char_t *row;
  670 
  671         KASSERT(p->tp_row < vb->vb_scr_size.tp_row,
  672             ("vtbuf_putchar tp_row %d must be less than screen width %d",
  673                 p->tp_row, vb->vb_scr_size.tp_row));
  674         KASSERT(p->tp_col < vb->vb_scr_size.tp_col,
  675             ("vtbuf_putchar tp_col %d must be less than screen height %d",
  676                 p->tp_col, vb->vb_scr_size.tp_col));
  677 
  678         row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) %
  679             VTBUF_MAX_HEIGHT(vb)];
  680         if (row[p->tp_col] != c) {
  681                 row[p->tp_col] = c;
  682                 vtbuf_dirty_cell(vb, p);
  683         }
  684 }
  685 
  686 void
  687 vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p)
  688 {
  689         if (vb->vb_flags & VBF_CURSOR) {
  690                 vtbuf_dirty_cell(vb, &vb->vb_cursor);
  691                 vb->vb_cursor = *p;
  692                 vtbuf_dirty_cell(vb, &vb->vb_cursor);
  693         } else {
  694                 vb->vb_cursor = *p;
  695         }
  696 }
  697 
  698 #ifndef SC_NO_CUTPASTE
  699 static void
  700 vtbuf_flush_mark(struct vt_buf *vb)
  701 {
  702         term_rect_t area;
  703         int s, e;
  704 
  705         /* Notify renderer to update marked region. */
  706         if ((vb->vb_mark_start.tp_col != vb->vb_mark_end.tp_col) ||
  707             (vb->vb_mark_start.tp_row != vb->vb_mark_end.tp_row)) {
  708                 s = vtbuf_htw(vb, vb->vb_mark_start.tp_row);
  709                 e = vtbuf_htw(vb, vb->vb_mark_end.tp_row);
  710 
  711                 area.tr_begin.tp_col = 0;
  712                 area.tr_begin.tp_row = MIN(s, e);
  713 
  714                 area.tr_end.tp_col = vb->vb_scr_size.tp_col;
  715                 area.tr_end.tp_row = MAX(s, e) + 1;
  716 
  717                 VTBUF_LOCK(vb);
  718                 vtbuf_dirty(vb, &area);
  719                 VTBUF_UNLOCK(vb);
  720         }
  721 }
  722 
  723 int
  724 vtbuf_get_marked_len(struct vt_buf *vb)
  725 {
  726         int ei, si, sz;
  727         term_pos_t s, e;
  728 
  729         /* Swap according to window coordinates. */
  730         if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row),
  731             vb->vb_mark_start.tp_col) >
  732             POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row),
  733             vb->vb_mark_end.tp_col)) {
  734                 POS_COPY(e, vb->vb_mark_start);
  735                 POS_COPY(s, vb->vb_mark_end);
  736         } else {
  737                 POS_COPY(s, vb->vb_mark_start);
  738                 POS_COPY(e, vb->vb_mark_end);
  739         }
  740 
  741         si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col;
  742         ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col;
  743 
  744         /* Number symbols and number of rows to inject \r */
  745         sz = ei - si + (1 + e.tp_row - s.tp_row);
  746 
  747         return (sz * sizeof(term_char_t));
  748 }
  749 
  750 static bool
  751 tchar_is_word_separator(term_char_t ch)
  752 {
  753         /* List of unicode word separator characters: */
  754         switch (TCHAR_CHARACTER(ch)) {
  755         case 0x0020: /* SPACE */
  756         case 0x180E: /* MONGOLIAN VOWEL SEPARATOR */
  757         case 0x2002: /* EN SPACE (nut) */
  758         case 0x2003: /* EM SPACE (mutton) */
  759         case 0x2004: /* THREE-PER-EM SPACE (thick space) */
  760         case 0x2005: /* FOUR-PER-EM SPACE (mid space) */
  761         case 0x2006: /* SIX-PER-EM SPACE */
  762         case 0x2008: /* PUNCTUATION SPACE */
  763         case 0x2009: /* THIN SPACE */
  764         case 0x200A: /* HAIR SPACE */
  765         case 0x200B: /* ZERO WIDTH SPACE */
  766         case 0x3000: /* IDEOGRAPHIC SPACE */
  767                 return (true);
  768         default:
  769                 return (false);
  770         }
  771 }
  772 
  773 void
  774 vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz, int mark)
  775 {
  776         int i, j, r, c, cs, ce;
  777         term_pos_t s, e;
  778 
  779         /* Swap according to window coordinates. */
  780         if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row),
  781             vb->vb_mark_start.tp_col) >
  782             POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row),
  783             vb->vb_mark_end.tp_col)) {
  784                 POS_COPY(e, vb->vb_mark_start);
  785                 POS_COPY(s, vb->vb_mark_end);
  786         } else {
  787                 POS_COPY(s, vb->vb_mark_start);
  788                 POS_COPY(e, vb->vb_mark_end);
  789         }
  790 
  791         i = 0;
  792         for (r = s.tp_row; r <= e.tp_row; r++) {
  793                 cs = (r == s.tp_row)?s.tp_col:0;
  794                 ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col;
  795 
  796                 /* Copy characters from terminal window. */
  797                 j = i;
  798                 for (c = cs; c < ce; c++)
  799                         buf[i++] = vb->vb_rows[r][c];
  800 
  801                 /* For all rows, but the last one. */
  802                 if (r != e.tp_row || mark == VTB_MARK_ROW) {
  803                         /* Trim trailing word separators, if any. */
  804                         for (; i != j; i--) {
  805                                 if (!tchar_is_word_separator(buf[i - 1]))
  806                                         break;
  807                         }
  808                         /* Add newline character as expected by TTY. */
  809                         buf[i++] = '\r';
  810                 }
  811         }
  812         /* Zero rest of expected buffer size, if any. */
  813         while ((i * sizeof(buf[0])) < sz)
  814                 buf[i++] = '\0';
  815 
  816         MPASS((i * sizeof(buf[0])) == sz);
  817 }
  818 
  819 int
  820 vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row)
  821 {
  822         term_char_t *r;
  823         int i;
  824 
  825         switch (type) {
  826         case VTB_MARK_END:      /* B1 UP */
  827                 if (vb->vb_mark_last != VTB_MARK_MOVE)
  828                         return (0);
  829                 /* FALLTHROUGH */
  830         case VTB_MARK_MOVE:
  831         case VTB_MARK_EXTEND:
  832                 vtbuf_flush_mark(vb); /* Clean old mark. */
  833                 vb->vb_mark_end.tp_col = col;
  834                 vb->vb_mark_end.tp_row = vtbuf_wth(vb, row);
  835                 break;
  836         case VTB_MARK_START:
  837                 vtbuf_flush_mark(vb); /* Clean old mark. */
  838                 vb->vb_mark_start.tp_col = col;
  839                 vb->vb_mark_start.tp_row = vtbuf_wth(vb, row);
  840                 /* Start again, so clear end point. */
  841                 vb->vb_mark_end.tp_col = col;
  842                 vb->vb_mark_end.tp_row = vtbuf_wth(vb, row);
  843                 break;
  844         case VTB_MARK_WORD:
  845                 vtbuf_flush_mark(vb); /* Clean old mark. */
  846                 vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row =
  847                     vtbuf_wth(vb, row);
  848                 r = vb->vb_rows[vb->vb_mark_start.tp_row];
  849                 for (i = col; i >= 0; i --) {
  850                         if (tchar_is_word_separator(r[i])) {
  851                                 vb->vb_mark_start.tp_col = i + 1;
  852                                 break;
  853                         }
  854                 }
  855                 /* No space - word extends to beginning of line. */
  856                 if (i == -1)
  857                         vb->vb_mark_start.tp_col = 0;
  858                 for (i = col; i < vb->vb_scr_size.tp_col; i++) {
  859                         if (tchar_is_word_separator(r[i])) {
  860                                 vb->vb_mark_end.tp_col = i;
  861                                 break;
  862                         }
  863                 }
  864                 /* No space - word extends to end of line. */
  865                 if (i == vb->vb_scr_size.tp_col)
  866                         vb->vb_mark_end.tp_col = i;
  867 
  868                 if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col)
  869                         vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col;
  870                 break;
  871         case VTB_MARK_ROW:
  872                 vtbuf_flush_mark(vb); /* Clean old mark. */
  873                 vb->vb_mark_start.tp_col = 0;
  874                 vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col;
  875                 vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row =
  876                     vtbuf_wth(vb, row);
  877                 break;
  878         case VTB_MARK_NONE:
  879                 vb->vb_mark_last = type;
  880                 /* FALLTHROUGH */
  881         default:
  882                 /* panic? */
  883                 return (0);
  884         }
  885 
  886         vb->vb_mark_last = type;
  887         /* Draw new marked region. */
  888         vtbuf_flush_mark(vb);
  889         return (1);
  890 }
  891 #endif
  892 
  893 void
  894 vtbuf_cursor_visibility(struct vt_buf *vb, int yes)
  895 {
  896         int oflags, nflags;
  897 
  898         oflags = vb->vb_flags;
  899         if (yes)
  900                 vb->vb_flags |= VBF_CURSOR;
  901         else
  902                 vb->vb_flags &= ~VBF_CURSOR;
  903         nflags = vb->vb_flags;
  904 
  905         if (oflags != nflags)
  906                 vtbuf_dirty_cell(vb, &vb->vb_cursor);
  907 }
  908 
  909 void
  910 vtbuf_scroll_mode(struct vt_buf *vb, int yes)
  911 {
  912         int oflags, nflags;
  913 
  914         VTBUF_LOCK(vb);
  915         oflags = vb->vb_flags;
  916         if (yes)
  917                 vb->vb_flags |= VBF_SCROLL;
  918         else
  919                 vb->vb_flags &= ~VBF_SCROLL;
  920         nflags = vb->vb_flags;
  921 
  922         if (oflags != nflags)
  923                 vtbuf_dirty_cell(vb, &vb->vb_cursor);
  924         VTBUF_UNLOCK(vb);
  925 }

Cache object: bd31fbb049f26bb8c09feb81b4f2cbbb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.