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/teken/teken.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  * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/10.2/sys/teken/teken.c 262861 2014-03-06 18:30:56Z jhb $
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 #if defined(__FreeBSD__) && defined(_KERNEL)
   31 #include <sys/param.h>
   32 #include <sys/lock.h>
   33 #include <sys/systm.h>
   34 #define teken_assert(x)         MPASS(x)
   35 #else /* !(__FreeBSD__ && _KERNEL) */
   36 #include <sys/types.h>
   37 #include <assert.h>
   38 #include <stdint.h>
   39 #include <stdio.h>
   40 #include <string.h>
   41 #define teken_assert(x)         assert(x)
   42 #endif /* __FreeBSD__ && _KERNEL */
   43 
   44 /* debug messages */
   45 #define teken_printf(x,...)
   46 
   47 /* Private flags for t_stateflags. */
   48 #define TS_FIRSTDIGIT   0x0001  /* First numeric digit in escape sequence. */
   49 #define TS_INSERT       0x0002  /* Insert mode. */
   50 #define TS_AUTOWRAP     0x0004  /* Autowrap. */
   51 #define TS_ORIGIN       0x0008  /* Origin mode. */
   52 #define TS_WRAPPED      0x0010  /* Next character should be printed on col 0. */
   53 #define TS_8BIT         0x0020  /* UTF-8 disabled. */
   54 #define TS_CONS25       0x0040  /* cons25 emulation. */
   55 #define TS_INSTRING     0x0080  /* Inside string. */
   56 #define TS_CURSORKEYS   0x0100  /* Cursor keys mode. */
   57 
   58 /* Character that blanks a cell. */
   59 #define BLANK   ' '
   60 
   61 #include "teken.h"
   62 #include "teken_wcwidth.h"
   63 #include "teken_scs.h"
   64 
   65 static teken_state_t    teken_state_init;
   66 
   67 /*
   68  * Wrappers for hooks.
   69  */
   70 
   71 static inline void
   72 teken_funcs_bell(teken_t *t)
   73 {
   74 
   75         t->t_funcs->tf_bell(t->t_softc);
   76 }
   77 
   78 static inline void
   79 teken_funcs_cursor(teken_t *t)
   80 {
   81 
   82         teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
   83         teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
   84 
   85         t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
   86 }
   87 
   88 static inline void
   89 teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
   90     const teken_attr_t *a)
   91 {
   92 
   93         teken_assert(p->tp_row < t->t_winsize.tp_row);
   94         teken_assert(p->tp_col < t->t_winsize.tp_col);
   95 
   96         t->t_funcs->tf_putchar(t->t_softc, p, c, a);
   97 }
   98 
   99 static inline void
  100 teken_funcs_fill(teken_t *t, const teken_rect_t *r,
  101     const teken_char_t c, const teken_attr_t *a)
  102 {
  103 
  104         teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
  105         teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
  106         teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
  107         teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
  108 
  109         t->t_funcs->tf_fill(t->t_softc, r, c, a);
  110 }
  111 
  112 static inline void
  113 teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
  114 {
  115 
  116         teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
  117         teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
  118         teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
  119         teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
  120         teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
  121         teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
  122 
  123         t->t_funcs->tf_copy(t->t_softc, r, p);
  124 }
  125 
  126 static inline void
  127 teken_funcs_param(teken_t *t, int cmd, unsigned int value)
  128 {
  129 
  130         t->t_funcs->tf_param(t->t_softc, cmd, value);
  131 }
  132 
  133 static inline void
  134 teken_funcs_respond(teken_t *t, const void *buf, size_t len)
  135 {
  136 
  137         t->t_funcs->tf_respond(t->t_softc, buf, len);
  138 }
  139 
  140 #include "teken_subr.h"
  141 #include "teken_subr_compat.h"
  142 
  143 /*
  144  * Programming interface.
  145  */
  146 
  147 void
  148 teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
  149 {
  150         teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
  151 
  152         t->t_funcs = tf;
  153         t->t_softc = softc;
  154 
  155         t->t_nextstate = teken_state_init;
  156         t->t_stateflags = 0;
  157         t->t_utf8_left = 0;
  158 
  159         t->t_defattr.ta_format = 0;
  160         t->t_defattr.ta_fgcolor = TC_WHITE;
  161         t->t_defattr.ta_bgcolor = TC_BLACK;
  162         teken_subr_do_reset(t);
  163 
  164         teken_set_winsize(t, &tp);
  165 }
  166 
  167 static void
  168 teken_input_char(teken_t *t, teken_char_t c)
  169 {
  170 
  171         /*
  172          * There is no support for DCS and OSC.  Just discard strings
  173          * until we receive characters that may indicate string
  174          * termination.
  175          */
  176         if (t->t_stateflags & TS_INSTRING) {
  177                 switch (c) {
  178                 case '\x1B':
  179                         t->t_stateflags &= ~TS_INSTRING;
  180                         break;
  181                 case '\a':
  182                         t->t_stateflags &= ~TS_INSTRING;
  183                         return;
  184                 default:
  185                         return;
  186                 }
  187         }
  188 
  189         switch (c) {
  190         case '\0':
  191                 break;
  192         case '\a':
  193                 teken_subr_bell(t);
  194                 break;
  195         case '\b':
  196                 teken_subr_backspace(t);
  197                 break;
  198         case '\n':
  199         case '\x0B':
  200                 teken_subr_newline(t);
  201                 break;
  202         case '\x0C':
  203                 teken_subr_newpage(t);
  204                 break;
  205         case '\x0E':
  206                 if (t->t_stateflags & TS_CONS25)
  207                         t->t_nextstate(t, c);
  208                 else
  209                         t->t_curscs = 1;
  210                 break;
  211         case '\x0F':
  212                 if (t->t_stateflags & TS_CONS25)
  213                         t->t_nextstate(t, c);
  214                 else
  215                         t->t_curscs = 0;
  216                 break;
  217         case '\r':
  218                 teken_subr_carriage_return(t);
  219                 break;
  220         case '\t':
  221                 teken_subr_horizontal_tab(t);
  222                 break;
  223         default:
  224                 t->t_nextstate(t, c);
  225                 break;
  226         }
  227 
  228         /* Post-processing assertions. */
  229         teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
  230         teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
  231         teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
  232         teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
  233         teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
  234         teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
  235         teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
  236         teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
  237         /* Origin region has to be window size or the same as scrollreg. */
  238         teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
  239             t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
  240             (t->t_originreg.ts_begin == 0 &&
  241             t->t_originreg.ts_end == t->t_winsize.tp_row));
  242 }
  243 
  244 static void
  245 teken_input_byte(teken_t *t, unsigned char c)
  246 {
  247 
  248         /*
  249          * UTF-8 handling.
  250          */
  251         if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) {
  252                 /* One-byte sequence. */
  253                 t->t_utf8_left = 0;
  254                 teken_input_char(t, c);
  255         } else if ((c & 0xe0) == 0xc0) {
  256                 /* Two-byte sequence. */
  257                 t->t_utf8_left = 1;
  258                 t->t_utf8_partial = c & 0x1f;
  259         } else if ((c & 0xf0) == 0xe0) {
  260                 /* Three-byte sequence. */
  261                 t->t_utf8_left = 2;
  262                 t->t_utf8_partial = c & 0x0f;
  263         } else if ((c & 0xf8) == 0xf0) {
  264                 /* Four-byte sequence. */
  265                 t->t_utf8_left = 3;
  266                 t->t_utf8_partial = c & 0x07;
  267         } else if ((c & 0xc0) == 0x80) {
  268                 if (t->t_utf8_left == 0)
  269                         return;
  270                 t->t_utf8_left--;
  271                 t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
  272                 if (t->t_utf8_left == 0) {
  273                         teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial);
  274                         teken_input_char(t, t->t_utf8_partial);
  275                 }
  276         }
  277 }
  278 
  279 void
  280 teken_input(teken_t *t, const void *buf, size_t len)
  281 {
  282         const char *c = buf;
  283 
  284         while (len-- > 0)
  285                 teken_input_byte(t, *c++);
  286 }
  287 
  288 const teken_pos_t *
  289 teken_get_cursor(teken_t *t)
  290 {
  291 
  292         return (&t->t_cursor);
  293 }
  294 
  295 void
  296 teken_set_cursor(teken_t *t, const teken_pos_t *p)
  297 {
  298 
  299         /* XXX: bounds checking with originreg! */
  300         teken_assert(p->tp_row < t->t_winsize.tp_row);
  301         teken_assert(p->tp_col < t->t_winsize.tp_col);
  302 
  303         t->t_cursor = *p;
  304 }
  305 
  306 const teken_attr_t *
  307 teken_get_curattr(teken_t *t)
  308 {
  309 
  310         return (&t->t_curattr);
  311 }
  312 
  313 void
  314 teken_set_curattr(teken_t *t, const teken_attr_t *a)
  315 {
  316 
  317         t->t_curattr = *a;
  318 }
  319 
  320 const teken_attr_t *
  321 teken_get_defattr(teken_t *t)
  322 {
  323 
  324         return (&t->t_defattr);
  325 }
  326 
  327 void
  328 teken_set_defattr(teken_t *t, const teken_attr_t *a)
  329 {
  330 
  331         t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
  332 }
  333 
  334 const teken_pos_t *
  335 teken_get_winsize(teken_t *t)
  336 {
  337 
  338         return (&t->t_winsize);
  339 }
  340 
  341 static void
  342 teken_trim_cursor_pos(teken_t *t, const teken_pos_t *new)
  343 {
  344         const teken_pos_t *cur;
  345 
  346         cur = &t->t_winsize;
  347 
  348         if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col)
  349                 return;
  350         if (t->t_cursor.tp_row >= new->tp_row)
  351                 t->t_cursor.tp_row = new->tp_row - 1;
  352         if (t->t_cursor.tp_col >= new->tp_col)
  353                 t->t_cursor.tp_col = new->tp_col - 1;
  354 }
  355 
  356 void
  357 teken_set_winsize(teken_t *t, const teken_pos_t *p)
  358 {
  359 
  360         teken_trim_cursor_pos(t, p);
  361         t->t_winsize = *p;
  362         teken_subr_do_reset(t);
  363 }
  364 
  365 void
  366 teken_set_winsize_noreset(teken_t *t, const teken_pos_t *p)
  367 {
  368 
  369         teken_trim_cursor_pos(t, p);
  370         t->t_winsize = *p;
  371         teken_subr_do_resize(t);
  372 }
  373 
  374 void
  375 teken_set_8bit(teken_t *t)
  376 {
  377 
  378         t->t_stateflags |= TS_8BIT;
  379 }
  380 
  381 void
  382 teken_set_cons25(teken_t *t)
  383 {
  384 
  385         t->t_stateflags |= TS_CONS25;
  386 }
  387 
  388 /*
  389  * State machine.
  390  */
  391 
  392 static void
  393 teken_state_switch(teken_t *t, teken_state_t *s)
  394 {
  395 
  396         t->t_nextstate = s;
  397         t->t_curnum = 0;
  398         t->t_stateflags |= TS_FIRSTDIGIT;
  399 }
  400 
  401 static int
  402 teken_state_numbers(teken_t *t, teken_char_t c)
  403 {
  404 
  405         teken_assert(t->t_curnum < T_NUMSIZE);
  406 
  407         if (c >= '' && c <= '9') {
  408                 /*
  409                  * Don't do math with the default value of 1 when a
  410                  * custom number is inserted.
  411                  */
  412                 if (t->t_stateflags & TS_FIRSTDIGIT) {
  413                         t->t_stateflags &= ~TS_FIRSTDIGIT;
  414                         t->t_nums[t->t_curnum] = 0;
  415                 } else {
  416                         t->t_nums[t->t_curnum] *= 10;
  417                 }
  418 
  419                 t->t_nums[t->t_curnum] += c - '';
  420                 return (1);
  421         } else if (c == ';') {
  422                 if (t->t_stateflags & TS_FIRSTDIGIT)
  423                         t->t_nums[t->t_curnum] = 0;
  424 
  425                 /* Only allow a limited set of arguments. */
  426                 if (++t->t_curnum == T_NUMSIZE) {
  427                         teken_state_switch(t, teken_state_init);
  428                         return (1);
  429                 }
  430 
  431                 t->t_stateflags |= TS_FIRSTDIGIT;
  432                 return (1);
  433         } else {
  434                 if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
  435                         /* Finish off the last empty argument. */
  436                         t->t_nums[t->t_curnum] = 0;
  437                         t->t_curnum++;
  438                 } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
  439                         /* Also count the last argument. */
  440                         t->t_curnum++;
  441                 }
  442         }
  443 
  444         return (0);
  445 }
  446 
  447 teken_color_t
  448 teken_256to8(teken_color_t c)
  449 {
  450         unsigned int r, g, b;
  451 
  452         if (c < 16) {
  453                 /* Traditional color indices. */
  454                 return (c % 8);
  455         } else if (c >= 244) {
  456                 /* Upper grayscale colors. */
  457                 return (TC_WHITE);
  458         } else if (c >= 232) {
  459                 /* Lower grayscale colors. */
  460                 return (TC_BLACK);
  461         }
  462 
  463         /* Convert to RGB. */
  464         c -= 16;
  465         b = c % 6;
  466         g = (c / 6) % 6;
  467         r = c / 36;
  468 
  469         if (r < g) {
  470                 /* Possibly green. */
  471                 if (g < b)
  472                         return (TC_BLUE);
  473                 else if (g > b)
  474                         return (TC_GREEN);
  475                 else
  476                         return (TC_CYAN);
  477         } else if (r > g) {
  478                 /* Possibly red. */
  479                 if (r < b)
  480                         return (TC_BLUE);
  481                 else if (r > b)
  482                         return (TC_RED);
  483                 else
  484                         return (TC_MAGENTA);
  485         } else {
  486                 /* Possibly brown. */
  487                 if (g < b)
  488                         return (TC_BLUE);
  489                 else if (g > b)
  490                         return (TC_BROWN);
  491                 else if (r < 3)
  492                         return (TC_BLACK);
  493                 else
  494                         return (TC_WHITE);
  495         }
  496 }
  497 
  498 static const char * const special_strings_cons25[] = {
  499         [TKEY_UP] = "\x1B[A",           [TKEY_DOWN] = "\x1B[B",
  500         [TKEY_LEFT] = "\x1B[D",         [TKEY_RIGHT] = "\x1B[C",
  501 
  502         [TKEY_HOME] = "\x1B[H",         [TKEY_END] = "\x1B[F",
  503         [TKEY_INSERT] = "\x1B[L",       [TKEY_DELETE] = "\x7F",
  504         [TKEY_PAGE_UP] = "\x1B[I",      [TKEY_PAGE_DOWN] = "\x1B[G",
  505 
  506         [TKEY_F1] = "\x1B[M",           [TKEY_F2] = "\x1B[N",
  507         [TKEY_F3] = "\x1B[O",           [TKEY_F4] = "\x1B[P",
  508         [TKEY_F5] = "\x1B[Q",           [TKEY_F6] = "\x1B[R",
  509         [TKEY_F7] = "\x1B[S",           [TKEY_F8] = "\x1B[T",
  510         [TKEY_F9] = "\x1B[U",           [TKEY_F10] = "\x1B[V",
  511         [TKEY_F11] = "\x1B[W",          [TKEY_F12] = "\x1B[X",
  512 };
  513 
  514 static const char * const special_strings_ckeys[] = {
  515         [TKEY_UP] = "\x1BOA",           [TKEY_DOWN] = "\x1BOB",
  516         [TKEY_LEFT] = "\x1BOD",         [TKEY_RIGHT] = "\x1BOC",
  517 
  518         [TKEY_HOME] = "\x1BOH",         [TKEY_END] = "\x1BOF",
  519 };
  520 
  521 static const char * const special_strings_normal[] = {
  522         [TKEY_UP] = "\x1B[A",           [TKEY_DOWN] = "\x1B[B",
  523         [TKEY_LEFT] = "\x1B[D",         [TKEY_RIGHT] = "\x1B[C",
  524 
  525         [TKEY_HOME] = "\x1B[H",         [TKEY_END] = "\x1B[F",
  526         [TKEY_INSERT] = "\x1B[2~",      [TKEY_DELETE] = "\x1B[3~",
  527         [TKEY_PAGE_UP] = "\x1B[5~",     [TKEY_PAGE_DOWN] = "\x1B[6~",
  528 
  529         [TKEY_F1] = "\x1BOP",           [TKEY_F2] = "\x1BOQ",
  530         [TKEY_F3] = "\x1BOR",           [TKEY_F4] = "\x1BOS",
  531         [TKEY_F5] = "\x1B[15~",         [TKEY_F6] = "\x1B[17~",
  532         [TKEY_F7] = "\x1B[18~",         [TKEY_F8] = "\x1B[19~",
  533         [TKEY_F9] = "\x1B[20~",         [TKEY_F10] = "\x1B[21~",
  534         [TKEY_F11] = "\x1B[23~",        [TKEY_F12] = "\x1B[24~",
  535 };
  536 
  537 const char *
  538 teken_get_sequence(teken_t *t, unsigned int k)
  539 {
  540 
  541         /* Cons25 mode. */
  542         if (t->t_stateflags & TS_CONS25 &&
  543             k < sizeof special_strings_cons25 / sizeof(char *))
  544                 return (special_strings_cons25[k]);
  545 
  546         /* Cursor keys mode. */
  547         if (t->t_stateflags & TS_CURSORKEYS &&
  548             k < sizeof special_strings_ckeys / sizeof(char *))
  549                 return (special_strings_ckeys[k]);
  550 
  551         /* Default xterm sequences. */
  552         if (k < sizeof special_strings_normal / sizeof(char *))
  553                 return (special_strings_normal[k]);
  554 
  555         return (NULL);
  556 }
  557 
  558 #include "teken_state.h"

Cache object: 553a4215c5cb801673023f76ffd573be


[ 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.