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/kern/tty_subr.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 /*      $NetBSD: tty_subr.c,v 1.43 2019/12/27 09:41:51 msaitoh Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1993, 1994 Theo de Raadt
    5  * All rights reserved.
    6  *
    7  * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
    8  * set of true clist functions that this is very loosely based on.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __KERNEL_RCSID(0, "$NetBSD: tty_subr.c,v 1.43 2019/12/27 09:41:51 msaitoh Exp $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/buf.h>
   37 #include <sys/ioctl.h>
   38 #include <sys/tty.h>
   39 #include <sys/kmem.h>
   40 
   41 /*
   42  * At compile time, choose:
   43  * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
   44  * defined we allocate an array of bits -- 1/8th as much memory but
   45  * setbit(), clrbit(), and isset() take more CPU. If QBITS is
   46  * undefined, we just use an array of bytes.
   47  *
   48  * If TTY_QUOTE functionality isn't required by a line discipline,
   49  * it can free c_cq and set it to NULL. This speeds things up,
   50  * and also does not use any extra memory. This is useful for (say)
   51  * a SLIP line discipline that wants a 32K ring buffer for data
   52  * but doesn't need quoting.
   53  */
   54 #define QBITS
   55 
   56 #ifdef QBITS
   57 #define QMEM(n)         ((((n)-1)/NBBY)+1)
   58 #else
   59 #define QMEM(n)         (n)
   60 #endif
   61 
   62 #ifdef QBITS
   63 static void     clrbits(u_char *, unsigned int, unsigned int);
   64 #endif
   65 
   66 /*
   67  * Initialize a particular clist. Ok, they are really ring buffers,
   68  * of the specified length, with/without quoting support.
   69  */
   70 int
   71 clalloc(struct clist *clp, int size, int quot)
   72 {
   73 
   74         clp->c_cs = kmem_zalloc(size, KM_SLEEP);
   75         if (quot)
   76                 clp->c_cq = kmem_zalloc(QMEM(size), KM_SLEEP);
   77         else
   78                 clp->c_cq = NULL;
   79 
   80         clp->c_cf = clp->c_cl = NULL;
   81         clp->c_ce = clp->c_cs + size;
   82         clp->c_cn = size;
   83         clp->c_cc = 0;
   84 
   85         return (0);
   86 }
   87 
   88 void
   89 clfree(struct clist *clp)
   90 {
   91         if (clp->c_cs)
   92                 kmem_free(clp->c_cs, clp->c_cn);
   93         if (clp->c_cq)
   94                 kmem_free(clp->c_cq, QMEM(clp->c_cn));
   95         clp->c_cs = clp->c_cq = NULL;
   96 }
   97 
   98 /*
   99  * Get a character from a clist.
  100  */
  101 int
  102 getc(struct clist *clp)
  103 {
  104         int c = -1;
  105         int s;
  106 
  107         s = spltty();
  108         if (clp->c_cc == 0)
  109                 goto out;
  110 
  111         c = *clp->c_cf & 0xff;
  112         if (clp->c_cq) {
  113 #ifdef QBITS
  114                 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
  115                         c |= TTY_QUOTE;
  116 #else
  117                 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
  118                         c |= TTY_QUOTE;
  119 #endif
  120         }
  121         *clp->c_cf = 0; /* wipe out to avoid information disclosure */
  122         if (++clp->c_cf == clp->c_ce)
  123                 clp->c_cf = clp->c_cs;
  124         if (--clp->c_cc == 0)
  125                 clp->c_cf = clp->c_cl = (u_char *)0;
  126 out:
  127         splx(s);
  128         return c;
  129 }
  130 
  131 /*
  132  * Copy clist to buffer.
  133  * Return number of bytes moved.
  134  */
  135 int
  136 q_to_b(struct clist *clp, u_char *cp, int count)
  137 {
  138         int cc;
  139         u_char *p = cp;
  140         int s;
  141 
  142         s = spltty();
  143         /* optimize this while loop */
  144         while (count > 0 && clp->c_cc > 0) {
  145                 cc = clp->c_cl - clp->c_cf;
  146                 if (clp->c_cf >= clp->c_cl)
  147                         cc = clp->c_ce - clp->c_cf;
  148                 if (cc > count)
  149                         cc = count;
  150                 memcpy(p, clp->c_cf, cc);
  151                 count -= cc;
  152                 p += cc;
  153                 clp->c_cc -= cc;
  154                 clp->c_cf += cc;
  155                 if (clp->c_cf == clp->c_ce)
  156                         clp->c_cf = clp->c_cs;
  157         }
  158         if (clp->c_cc == 0)
  159                 clp->c_cf = clp->c_cl = (u_char *)0;
  160         splx(s);
  161         return p - cp;
  162 }
  163 
  164 /*
  165  * Return count of contiguous characters in clist.
  166  * Stop counting if flag&character is non-null.
  167  */
  168 int
  169 ndqb(struct clist *clp, int flag)
  170 {
  171         int count = 0;
  172         int i;
  173         int cc;
  174         int s;
  175 
  176         s = spltty();
  177         if ((cc = clp->c_cc) == 0)
  178                 goto out;
  179 
  180         if (flag == 0) {
  181                 count = clp->c_cl - clp->c_cf;
  182                 if (count <= 0)
  183                         count = clp->c_ce - clp->c_cf;
  184                 goto out;
  185         }
  186 
  187         i = clp->c_cf - clp->c_cs;
  188         if (flag & TTY_QUOTE) {
  189                 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
  190                     isset(clp->c_cq, i))) {
  191                         count++;
  192                         if (i == clp->c_cn)
  193                                 break;
  194                 }
  195         } else {
  196                 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
  197                         count++;
  198                         if (i == clp->c_cn)
  199                                 break;
  200                 }
  201         }
  202 out:
  203         splx(s);
  204         return count;
  205 }
  206 
  207 /*
  208  * Flush count bytes from clist.
  209  */
  210 void
  211 ndflush(struct clist *clp, int count)
  212 {
  213         int cc;
  214         int s;
  215 
  216         s = spltty();
  217         if (count == clp->c_cc) {
  218                 clp->c_cc = 0;
  219                 clp->c_cf = clp->c_cl = (u_char *)0;
  220                 goto out;
  221         }
  222         /* optimize this while loop */
  223         while (count > 0 && clp->c_cc > 0) {
  224                 cc = clp->c_cl - clp->c_cf;
  225                 if (clp->c_cf >= clp->c_cl)
  226                         cc = clp->c_ce - clp->c_cf;
  227                 if (cc > count)
  228                         cc = count;
  229                 count -= cc;
  230                 clp->c_cc -= cc;
  231                 clp->c_cf += cc;
  232                 if (clp->c_cf == clp->c_ce)
  233                         clp->c_cf = clp->c_cs;
  234         }
  235         if (clp->c_cc == 0)
  236                 clp->c_cf = clp->c_cl = (u_char *)0;
  237 out:
  238         splx(s);
  239 }
  240 
  241 /*
  242  * Put a character into the output queue.
  243  */
  244 int
  245 putc(int c, struct clist *clp)
  246 {
  247         int i;
  248         int s;
  249 
  250         s = spltty();
  251         if (clp->c_cc == clp->c_cn)
  252                 goto out;
  253 
  254         if (clp->c_cc == 0) {
  255                 if (!clp->c_cs) {
  256 #if defined(DIAGNOSTIC) || 1
  257                         printf("putc: required clalloc\n");
  258 #endif
  259                         if (clalloc(clp, clp->c_cn, 1)) {
  260 out:
  261                                 splx(s);
  262                                 return -1;
  263                         }
  264                 }
  265                 clp->c_cf = clp->c_cl = clp->c_cs;
  266         }
  267 
  268         *clp->c_cl = c & 0xff;
  269         i = clp->c_cl - clp->c_cs;
  270         if (clp->c_cq) {
  271 #ifdef QBITS
  272                 if (c & TTY_QUOTE)
  273                         setbit(clp->c_cq, i);
  274                 else
  275                         clrbit(clp->c_cq, i);
  276 #else
  277                 q = clp->c_cq + i;
  278                 *q = (c & TTY_QUOTE) ? 1 : 0;
  279 #endif
  280         }
  281         clp->c_cc++;
  282         clp->c_cl++;
  283         if (clp->c_cl == clp->c_ce)
  284                 clp->c_cl = clp->c_cs;
  285         splx(s);
  286         return 0;
  287 }
  288 
  289 #ifdef QBITS
  290 /*
  291  * optimized version of
  292  *
  293  * for (i = 0; i < len; i++)
  294  *      clrbit(cp, off + len);
  295  */
  296 static void
  297 clrbits(u_char *cp, unsigned int off, unsigned int len)
  298 {
  299         unsigned int sbi, ebi;
  300         u_char *scp, *ecp;
  301         unsigned int end;
  302         unsigned char mask;
  303 
  304         scp = cp + off / NBBY;
  305         sbi = off % NBBY;
  306         end = off + len + NBBY - 1;
  307         ecp = cp + end / NBBY - 1;
  308         ebi = end % NBBY + 1;
  309         if (scp >= ecp) {
  310                 mask = ((1 << len) - 1) << sbi;
  311                 *scp &= ~mask;
  312         } else {
  313                 mask = (1 << sbi) - 1;
  314                 *scp++ &= mask;
  315 
  316                 mask = (1 << ebi) - 1;
  317                 *ecp &= ~mask;
  318 
  319                 while (scp < ecp)
  320                         *scp++ = 0x00;
  321         }
  322 }
  323 #endif
  324 
  325 /*
  326  * Copy buffer to clist.
  327  * Return number of bytes not transferred.
  328  */
  329 int
  330 b_to_q(const u_char *cp, int count, struct clist *clp)
  331 {
  332         int cc;
  333         const u_char *p = cp;
  334         int s;
  335 
  336         if (count <= 0)
  337                 return 0;
  338 
  339         s = spltty();
  340         if (clp->c_cc == clp->c_cn)
  341                 goto out;
  342 
  343         if (clp->c_cc == 0) {
  344                 if (!clp->c_cs) {
  345 #if defined(DIAGNOSTIC) || 1
  346                         printf("b_to_q: required clalloc\n");
  347 #endif
  348                         if (clalloc(clp, clp->c_cn, 1))
  349                                 goto out;
  350                 }
  351                 clp->c_cf = clp->c_cl = clp->c_cs;
  352         }
  353 
  354         /* optimize this while loop */
  355         while (count > 0 && clp->c_cc < clp->c_cn) {
  356                 cc = clp->c_ce - clp->c_cl;
  357                 if (clp->c_cf > clp->c_cl)
  358                         cc = clp->c_cf - clp->c_cl;
  359                 if (cc > count)
  360                         cc = count;
  361                 memcpy(clp->c_cl, p, cc);
  362                 if (clp->c_cq) {
  363 #ifdef QBITS
  364                         clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
  365 #else
  366                         memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, cc);
  367 #endif
  368                 }
  369                 p += cc;
  370                 count -= cc;
  371                 clp->c_cc += cc;
  372                 clp->c_cl += cc;
  373                 if (clp->c_cl == clp->c_ce)
  374                         clp->c_cl = clp->c_cs;
  375         }
  376 out:
  377         splx(s);
  378         return count;
  379 }
  380 
  381 static int tty_global_cc;
  382 
  383 /*
  384  * Given a non-NULL pointer into the clist return the pointer
  385  * to the next character in the list or return NULL if no more chars.
  386  *
  387  * Callers must not allow getc's to happen between firstc's and getc's
  388  * so that the pointer becomes invalid.  Note that interrupts are NOT
  389  * masked.
  390  */
  391 u_char *
  392 nextc(struct clist *clp, u_char *cp, int *c)
  393 {
  394 
  395         if (clp->c_cf == cp) {
  396                 /*
  397                  * First time initialization.
  398                  */
  399                 tty_global_cc = clp->c_cc;
  400         }
  401         if (tty_global_cc == 0 || cp == NULL)
  402                 return NULL;
  403         if (--tty_global_cc == 0)
  404                 return NULL;
  405         if (++cp == clp->c_ce)
  406                 cp = clp->c_cs;
  407         *c = *cp & 0xff;
  408         if (clp->c_cq) {
  409 #ifdef QBITS
  410                 if (isset(clp->c_cq, cp - clp->c_cs))
  411                         *c |= TTY_QUOTE;
  412 #else
  413                 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
  414                         *c |= TTY_QUOTE;
  415 #endif
  416         }
  417         return cp;
  418 }
  419 
  420 /*
  421  * Given a non-NULL pointer into the clist return the pointer
  422  * to the first character in the list or return NULL if no more chars.
  423  *
  424  * Callers must not allow getc's to happen between firstc's and getc's
  425  * so that the pointer becomes invalid.  Note that interrupts are NOT
  426  * masked.
  427  *
  428  * *c is set to the NEXT character
  429  */
  430 u_char *
  431 firstc(struct clist *clp, int *c)
  432 {
  433         u_char *cp;
  434 
  435         tty_global_cc = clp->c_cc;
  436         if (tty_global_cc == 0)
  437                 return NULL;
  438         cp = clp->c_cf;
  439         *c = *cp & 0xff;
  440         if (clp->c_cq) {
  441 #ifdef QBITS
  442                 if (isset(clp->c_cq, cp - clp->c_cs))
  443                         *c |= TTY_QUOTE;
  444 #else
  445                 if (*(cp - clp->c_cs + clp->c_cq))
  446                         *c |= TTY_QUOTE;
  447 #endif
  448         }
  449         return clp->c_cf;
  450 }
  451 
  452 /*
  453  * Remove the last character in the clist and return it.
  454  */
  455 int
  456 unputc(struct clist *clp)
  457 {
  458         unsigned int c = -1;
  459         int s;
  460 
  461         s = spltty();
  462         if (clp->c_cc == 0)
  463                 goto out;
  464 
  465         if (clp->c_cl == clp->c_cs)
  466                 clp->c_cl = clp->c_ce - 1;
  467         else
  468                 --clp->c_cl;
  469         clp->c_cc--;
  470 
  471         c = *clp->c_cl & 0xff;
  472         if (clp->c_cq) {
  473 #ifdef QBITS
  474                 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
  475                         c |= TTY_QUOTE;
  476 #else
  477                 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
  478                         c |= TTY_QUOTE;
  479 #endif
  480         }
  481         if (clp->c_cc == 0)
  482                 clp->c_cf = clp->c_cl = (u_char *)0;
  483 out:
  484         splx(s);
  485         return c;
  486 }
  487 
  488 /*
  489  * Put the chars in the from queue on the end of the to queue.
  490  */
  491 void
  492 catq(struct clist *from, struct clist *to)
  493 {
  494         int c;
  495 
  496         while ((c = getc(from)) != -1)
  497                 putc(c, to);
  498 }

Cache object: e38fc807098e9cfe881014a139c4d264


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