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.0/sys/teken/teken.c 223574 2011-06-26 18:25:10Z ed $
   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 void
  342 teken_set_winsize(teken_t *t, const teken_pos_t *p)
  343 {
  344 
  345         t->t_winsize = *p;
  346         teken_subr_do_reset(t);
  347 }
  348 
  349 void
  350 teken_set_8bit(teken_t *t)
  351 {
  352 
  353         t->t_stateflags |= TS_8BIT;
  354 }
  355 
  356 void
  357 teken_set_cons25(teken_t *t)
  358 {
  359 
  360         t->t_stateflags |= TS_CONS25;
  361 }
  362 
  363 /*
  364  * State machine.
  365  */
  366 
  367 static void
  368 teken_state_switch(teken_t *t, teken_state_t *s)
  369 {
  370 
  371         t->t_nextstate = s;
  372         t->t_curnum = 0;
  373         t->t_stateflags |= TS_FIRSTDIGIT;
  374 }
  375 
  376 static int
  377 teken_state_numbers(teken_t *t, teken_char_t c)
  378 {
  379 
  380         teken_assert(t->t_curnum < T_NUMSIZE);
  381 
  382         if (c >= '' && c <= '9') {
  383                 /*
  384                  * Don't do math with the default value of 1 when a
  385                  * custom number is inserted.
  386                  */
  387                 if (t->t_stateflags & TS_FIRSTDIGIT) {
  388                         t->t_stateflags &= ~TS_FIRSTDIGIT;
  389                         t->t_nums[t->t_curnum] = 0;
  390                 } else {
  391                         t->t_nums[t->t_curnum] *= 10;
  392                 }
  393 
  394                 t->t_nums[t->t_curnum] += c - '';
  395                 return (1);
  396         } else if (c == ';') {
  397                 if (t->t_stateflags & TS_FIRSTDIGIT)
  398                         t->t_nums[t->t_curnum] = 0;
  399 
  400                 /* Only allow a limited set of arguments. */
  401                 if (++t->t_curnum == T_NUMSIZE) {
  402                         teken_state_switch(t, teken_state_init);
  403                         return (1);
  404                 }
  405 
  406                 t->t_stateflags |= TS_FIRSTDIGIT;
  407                 return (1);
  408         } else {
  409                 if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
  410                         /* Finish off the last empty argument. */
  411                         t->t_nums[t->t_curnum] = 0;
  412                         t->t_curnum++;
  413                 } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
  414                         /* Also count the last argument. */
  415                         t->t_curnum++;
  416                 }
  417         }
  418 
  419         return (0);
  420 }
  421 
  422 teken_color_t
  423 teken_256to8(teken_color_t c)
  424 {
  425         unsigned int r, g, b;
  426 
  427         if (c < 16) {
  428                 /* Traditional color indices. */
  429                 return (c % 8);
  430         } else if (c >= 244) {
  431                 /* Upper grayscale colors. */
  432                 return (TC_WHITE);
  433         } else if (c >= 232) {
  434                 /* Lower grayscale colors. */
  435                 return (TC_BLACK);
  436         }
  437 
  438         /* Convert to RGB. */
  439         c -= 16;
  440         b = c % 6;
  441         g = (c / 6) % 6;
  442         r = c / 36;
  443 
  444         if (r < g) {
  445                 /* Possibly green. */
  446                 if (g < b)
  447                         return (TC_BLUE);
  448                 else if (g > b)
  449                         return (TC_GREEN);
  450                 else
  451                         return (TC_CYAN);
  452         } else if (r > g) {
  453                 /* Possibly red. */
  454                 if (r < b)
  455                         return (TC_BLUE);
  456                 else if (r > b)
  457                         return (TC_RED);
  458                 else
  459                         return (TC_MAGENTA);
  460         } else {
  461                 /* Possibly brown. */
  462                 if (g < b)
  463                         return (TC_BLUE);
  464                 else if (g > b)
  465                         return (TC_BROWN);
  466                 else if (r < 3)
  467                         return (TC_BLACK);
  468                 else
  469                         return (TC_WHITE);
  470         }
  471 }
  472 
  473 static const char * const special_strings_cons25[] = {
  474         [TKEY_UP] = "\x1B[A",           [TKEY_DOWN] = "\x1B[B",
  475         [TKEY_LEFT] = "\x1B[D",         [TKEY_RIGHT] = "\x1B[C",
  476 
  477         [TKEY_HOME] = "\x1B[H",         [TKEY_END] = "\x1B[F",
  478         [TKEY_INSERT] = "\x1B[L",       [TKEY_DELETE] = "\x7F",
  479         [TKEY_PAGE_UP] = "\x1B[I",      [TKEY_PAGE_DOWN] = "\x1B[G",
  480 
  481         [TKEY_F1] = "\x1B[M",           [TKEY_F2] = "\x1B[N",
  482         [TKEY_F3] = "\x1B[O",           [TKEY_F4] = "\x1B[P",
  483         [TKEY_F5] = "\x1B[Q",           [TKEY_F6] = "\x1B[R",
  484         [TKEY_F7] = "\x1B[S",           [TKEY_F8] = "\x1B[T",
  485         [TKEY_F9] = "\x1B[U",           [TKEY_F10] = "\x1B[V",
  486         [TKEY_F11] = "\x1B[W",          [TKEY_F12] = "\x1B[X",
  487 };
  488 
  489 static const char * const special_strings_ckeys[] = {
  490         [TKEY_UP] = "\x1BOA",           [TKEY_DOWN] = "\x1BOB",
  491         [TKEY_LEFT] = "\x1BOD",         [TKEY_RIGHT] = "\x1BOC",
  492 
  493         [TKEY_HOME] = "\x1BOH",         [TKEY_END] = "\x1BOF",
  494 };
  495 
  496 static const char * const special_strings_normal[] = {
  497         [TKEY_UP] = "\x1B[A",           [TKEY_DOWN] = "\x1B[B",
  498         [TKEY_LEFT] = "\x1B[D",         [TKEY_RIGHT] = "\x1B[C",
  499 
  500         [TKEY_HOME] = "\x1B[H",         [TKEY_END] = "\x1B[F",
  501         [TKEY_INSERT] = "\x1B[2~",      [TKEY_DELETE] = "\x1B[3~",
  502         [TKEY_PAGE_UP] = "\x1B[5~",     [TKEY_PAGE_DOWN] = "\x1B[6~",
  503 
  504         [TKEY_F1] = "\x1BOP",           [TKEY_F2] = "\x1BOQ",
  505         [TKEY_F3] = "\x1BOR",           [TKEY_F4] = "\x1BOS",
  506         [TKEY_F5] = "\x1B[15~",         [TKEY_F6] = "\x1B[17~",
  507         [TKEY_F7] = "\x1B[18~",         [TKEY_F8] = "\x1B[19~",
  508         [TKEY_F9] = "\x1B[20~",         [TKEY_F10] = "\x1B[21~",
  509         [TKEY_F11] = "\x1B[23~",        [TKEY_F12] = "\x1B[24~",
  510 };
  511 
  512 const char *
  513 teken_get_sequence(teken_t *t, unsigned int k)
  514 {
  515 
  516         /* Cons25 mode. */
  517         if (t->t_stateflags & TS_CONS25 &&
  518             k < sizeof special_strings_cons25 / sizeof(char *))
  519                 return (special_strings_cons25[k]);
  520 
  521         /* Cursor keys mode. */
  522         if (t->t_stateflags & TS_CURSORKEYS &&
  523             k < sizeof special_strings_ckeys / sizeof(char *))
  524                 return (special_strings_ckeys[k]);
  525 
  526         /* Default xterm sequences. */
  527         if (k < sizeof special_strings_normal / sizeof(char *))
  528                 return (special_strings_normal[k]);
  529 
  530         return (NULL);
  531 }
  532 
  533 #include "teken_state.h"

Cache object: 36ec0775fb23d9af23b076f7b0ca715c


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