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/ddb/db_input.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: MIT-CMU
    3  *
    4  * Mach Operating System
    5  * Copyright (c) 1991,1990 Carnegie Mellon University
    6  * All Rights Reserved.
    7  *
    8  * Permission to use, copy, modify and distribute this software and its
    9  * documentation is hereby granted, provided that both the copyright
   10  * notice and this permission notice appear in all copies of the
   11  * software, derivative works or modified versions, and any portions
   12  * thereof, and that both notices appear in supporting documentation.
   13  *
   14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
   15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   17  *
   18  * Carnegie Mellon requests users of this software to return to
   19  *
   20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   21  *  School of Computer Science
   22  *  Carnegie Mellon University
   23  *  Pittsburgh PA 15213-3890
   24  *
   25  * any improvements or extensions that they make and grant Carnegie the
   26  * rights to redistribute these changes.
   27  */
   28 /*
   29  *      Author: David B. Golub, Carnegie Mellon University
   30  *      Date:   7/90
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/cons.h>
   39 #include <sys/sysctl.h>
   40 
   41 #include <ddb/ddb.h>
   42 #include <ddb/db_output.h>
   43 
   44 /*
   45  * Character input and editing.
   46  */
   47 
   48 /*
   49  * We don't track output position while editing input,
   50  * since input always ends with a new-line.  We just
   51  * reset the line position at the end.
   52  */
   53 static char *   db_lbuf_start;  /* start of input line buffer */
   54 static char *   db_lbuf_end;    /* end of input line buffer */
   55 static char *   db_lc;          /* current character */
   56 static char *   db_le;          /* one past last character */
   57 
   58 /*
   59  * Raw input buffer, processed only for certain control characters.
   60  */
   61 #define DB_RAW_SIZE     512
   62 static char     db_raw[DB_RAW_SIZE];
   63 static u_int    db_raw_pos;
   64 static u_int    db_raw_cnt;
   65 static int      db_raw_warned;
   66 static int      ddb_prioritize_control_input = 1;
   67 SYSCTL_INT(_debug_ddb, OID_AUTO, prioritize_control_input, CTLFLAG_RWTUN,
   68     &ddb_prioritize_control_input, 0,
   69     "Drop input when the buffer fills in order to keep servicing ^C/^S/^Q");
   70 
   71 /*
   72  * Simple input line history support.
   73  */
   74 static char     db_lhistory[2048];
   75 static int      db_lhistlsize, db_lhistidx, db_lhistcur;
   76 static int      db_lhist_nlines;
   77 
   78 #define CTRL(c)         ((c) & 0x1f)
   79 #define BLANK           ' '
   80 #define BACKUP          '\b'
   81 
   82 static void     db_delete(int n, int bwd);
   83 static int      db_inputchar(int c);
   84 static void     db_putnchars(int c, int count);
   85 static void     db_putstring(char *s, int count);
   86 static int      db_raw_pop(void);
   87 static void     db_raw_push(int);
   88 static int      db_raw_space(void);
   89 
   90 static void
   91 db_putstring(s, count)
   92         char    *s;
   93         int     count;
   94 {
   95         while (--count >= 0)
   96             cnputc(*s++);
   97 }
   98 
   99 static void
  100 db_putnchars(c, count)
  101         int     c;
  102         int     count;
  103 {
  104         while (--count >= 0)
  105             cnputc(c);
  106 }
  107 
  108 /*
  109  * Delete N characters, forward or backward
  110  */
  111 #define DEL_FWD         0
  112 #define DEL_BWD         1
  113 static void
  114 db_delete(n, bwd)
  115         int     n;
  116         int     bwd;
  117 {
  118         char *p;
  119 
  120         if (bwd) {
  121             db_lc -= n;
  122             db_putnchars(BACKUP, n);
  123         }
  124         for (p = db_lc; p < db_le-n; p++) {
  125             *p = *(p+n);
  126             cnputc(*p);
  127         }
  128         db_putnchars(BLANK, n);
  129         db_putnchars(BACKUP, db_le - db_lc);
  130         db_le -= n;
  131 }
  132 
  133 /* returns true at end-of-line */
  134 static int
  135 db_inputchar(c)
  136         int     c;
  137 {
  138         static int escstate;
  139 
  140         if (escstate == 1) {
  141                 /* ESC seen, look for [ or O */
  142                 if (c == '[' || c == 'O')
  143                         escstate++;
  144                 else
  145                         escstate = 0; /* re-init state machine */
  146                 return (0);
  147         } else if (escstate == 2) {
  148                 escstate = 0;
  149                 /*
  150                  * If a valid cursor key has been found, translate
  151                  * into an emacs-style control key, and fall through.
  152                  * Otherwise, drop off.
  153                  */
  154                 switch (c) {
  155                 case 'A':       /* up */
  156                         c = CTRL('p');
  157                         break;
  158                 case 'B':       /* down */
  159                         c = CTRL('n');
  160                         break;
  161                 case 'C':       /* right */
  162                         c = CTRL('f');
  163                         break;
  164                 case 'D':       /* left */
  165                         c = CTRL('b');
  166                         break;
  167                 default:
  168                         return (0);
  169                 }
  170         }
  171 
  172         switch (c) {
  173             case CTRL('['):
  174                 escstate = 1;
  175                 break;
  176             case CTRL('b'):
  177                 /* back up one character */
  178                 if (db_lc > db_lbuf_start) {
  179                     cnputc(BACKUP);
  180                     db_lc--;
  181                 }
  182                 break;
  183             case CTRL('f'):
  184                 /* forward one character */
  185                 if (db_lc < db_le) {
  186                     cnputc(*db_lc);
  187                     db_lc++;
  188                 }
  189                 break;
  190             case CTRL('a'):
  191                 /* beginning of line */
  192                 while (db_lc > db_lbuf_start) {
  193                     cnputc(BACKUP);
  194                     db_lc--;
  195                 }
  196                 break;
  197             case CTRL('e'):
  198                 /* end of line */
  199                 while (db_lc < db_le) {
  200                     cnputc(*db_lc);
  201                     db_lc++;
  202                 }
  203                 break;
  204             case CTRL('h'):
  205             case 0177:
  206                 /* erase previous character */
  207                 if (db_lc > db_lbuf_start)
  208                     db_delete(1, DEL_BWD);
  209                 break;
  210             case CTRL('d'):
  211                 /* erase next character */
  212                 if (db_lc < db_le)
  213                     db_delete(1, DEL_FWD);
  214                 break;
  215             case CTRL('u'):
  216             case CTRL('c'):
  217                 /* kill entire line: */
  218                 /* at first, delete to beginning of line */
  219                 if (db_lc > db_lbuf_start)
  220                     db_delete(db_lc - db_lbuf_start, DEL_BWD);
  221                 /* FALLTHROUGH */
  222             case CTRL('k'):
  223                 /* delete to end of line */
  224                 if (db_lc < db_le)
  225                     db_delete(db_le - db_lc, DEL_FWD);
  226                 break;
  227             case CTRL('t'):
  228                 /* twiddle last 2 characters */
  229                 if (db_lc >= db_lbuf_start + 2) {
  230                     c = db_lc[-2];
  231                     db_lc[-2] = db_lc[-1];
  232                     db_lc[-1] = c;
  233                     cnputc(BACKUP);
  234                     cnputc(BACKUP);
  235                     cnputc(db_lc[-2]);
  236                     cnputc(db_lc[-1]);
  237                 }
  238                 break;
  239             case CTRL('w'):
  240                 /* erase previous word */
  241                 for (; db_lc > db_lbuf_start;) {
  242                     if (*(db_lc - 1) != ' ')
  243                         break;
  244                     db_delete(1, DEL_BWD);
  245                 }
  246                 for (; db_lc > db_lbuf_start;) {
  247                     if (*(db_lc - 1) == ' ')
  248                         break;
  249                     db_delete(1, DEL_BWD);
  250                 }
  251                 break;
  252             case CTRL('r'):
  253                 db_putstring("^R\n", 3);
  254             redraw:
  255                 if (db_le > db_lbuf_start) {
  256                     db_putstring(db_lbuf_start, db_le - db_lbuf_start);
  257                     db_putnchars(BACKUP, db_le - db_lc);
  258                 }
  259                 break;
  260             case CTRL('p'):
  261                 /* Make previous history line the active one. */
  262                 if (db_lhistcur >= 0) {
  263                     bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
  264                           db_lbuf_start, db_lhistlsize);
  265                     db_lhistcur--;
  266                     goto hist_redraw;
  267                 }
  268                 break;
  269             case CTRL('n'):
  270                 /* Make next history line the active one. */
  271                 if (db_lhistcur < db_lhistidx - 1) {
  272                     db_lhistcur += 2;
  273                     bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
  274                           db_lbuf_start, db_lhistlsize);
  275                 } else {
  276                     /*
  277                      * ^N through tail of history, reset the
  278                      * buffer to zero length.
  279                      */
  280                     *db_lbuf_start = '\0';
  281                     db_lhistcur = db_lhistidx;
  282                 }
  283 
  284             hist_redraw:
  285                 db_putnchars(BACKUP, db_lc - db_lbuf_start);
  286                 db_putnchars(BLANK, db_le - db_lbuf_start);
  287                 db_putnchars(BACKUP, db_le - db_lbuf_start);
  288                 db_le = strchr(db_lbuf_start, '\0');
  289                 if (db_le[-1] == '\r' || db_le[-1] == '\n')
  290                     *--db_le = '\0';
  291                 db_lc = db_le;
  292                 goto redraw;
  293 
  294             case -1:
  295                 /*
  296                  * eek! the console returned eof.
  297                  * probably that means we HAVE no console.. we should try bail
  298                  * XXX
  299                  */
  300                 c = '\r';
  301             case '\n':
  302                 /* FALLTHROUGH */
  303             case '\r':
  304                 *db_le++ = c;
  305                 return (1);
  306             default:
  307                 if (db_le == db_lbuf_end) {
  308                     cnputc('\007');
  309                 }
  310                 else if (c >= ' ' && c <= '~') {
  311                     char *p;
  312 
  313                     for (p = db_le; p > db_lc; p--)
  314                         *p = *(p-1);
  315                     *db_lc++ = c;
  316                     db_le++;
  317                     cnputc(c);
  318                     db_putstring(db_lc, db_le - db_lc);
  319                     db_putnchars(BACKUP, db_le - db_lc);
  320                 }
  321                 break;
  322         }
  323         return (0);
  324 }
  325 
  326 /* Get a character from the console, first checking the raw input buffer. */
  327 int
  328 db_getc(void)
  329 {
  330         int c;
  331 
  332         if (db_raw_cnt == 0) {
  333                 c = cngetc();
  334         } else {
  335                 c = db_raw_pop();
  336                 if (c == '\r')
  337                         c = '\n';
  338         }
  339         return (c);
  340 }
  341 
  342 /* Whether the raw input buffer has space to accept another character. */
  343 static int
  344 db_raw_space(void)
  345 {
  346 
  347         return (db_raw_cnt < DB_RAW_SIZE);
  348 }
  349 
  350 /* Un-get a character from the console by buffering it. */
  351 static void
  352 db_raw_push(int c)
  353 {
  354 
  355         if (!db_raw_space())
  356                 db_error(NULL);
  357         db_raw[(db_raw_pos + db_raw_cnt++) % DB_RAW_SIZE] = c;
  358 }
  359 
  360 /* Drain a character from the raw input buffer. */
  361 static int
  362 db_raw_pop(void)
  363 {
  364 
  365         if (db_raw_cnt == 0)
  366                 return (-1);
  367         db_raw_cnt--;
  368         db_raw_warned = 0;
  369         return (db_raw[db_raw_pos++ % DB_RAW_SIZE]);
  370 }
  371 
  372 int
  373 db_readline(lstart, lsize)
  374         char *  lstart;
  375         int     lsize;
  376 {
  377 
  378         if (lsize < 2)
  379                 return (0);
  380         if (lsize != db_lhistlsize) {
  381                 /*
  382                  * (Re)initialize input line history.  Throw away any
  383                  * existing history.
  384                  */
  385                 db_lhist_nlines = sizeof(db_lhistory) / lsize;
  386                 db_lhistlsize = lsize;
  387                 db_lhistidx = -1;
  388         }
  389         db_lhistcur = db_lhistidx;
  390 
  391         db_force_whitespace();  /* synch output position */
  392 
  393         db_lbuf_start = lstart;
  394         db_lbuf_end   = lstart + lsize - 2;     /* Will append NL and NUL. */
  395         db_lc = lstart;
  396         db_le = lstart;
  397 
  398         while (!db_inputchar(db_getc()))
  399             continue;
  400 
  401         db_capture_write(lstart, db_le - db_lbuf_start);
  402         db_printf("\n");        /* synch output position */
  403         *db_le = 0;
  404 
  405         if (db_le - db_lbuf_start > 1) {
  406             /* Maintain input line history for non-empty lines. */
  407             if (++db_lhistidx == db_lhist_nlines) {
  408                 /* Rotate history. */
  409                 bcopy(db_lhistory + db_lhistlsize, db_lhistory,
  410                       db_lhistlsize * (db_lhist_nlines - 1));
  411                 db_lhistidx--;
  412             }
  413             bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
  414                   db_lhistlsize);
  415         }
  416 
  417         return (db_le - db_lbuf_start);
  418 }
  419 
  420 static void
  421 db_do_interrupt(const char *reason)
  422 {
  423 
  424         /* Do a pager quit too because some commands have jmpbuf handling. */
  425         db_disable_pager();
  426         db_pager_quit = 1;
  427         db_error(reason);
  428 }
  429 
  430 void
  431 db_check_interrupt(void)
  432 {
  433         int     c;
  434 
  435         /*
  436          * Check console input for control characters.  Non-control input is
  437          * buffered.  When buffer space is exhausted, either stop responding to
  438          * control input or drop further non-control input on the floor.
  439          */
  440         for (;;) {
  441                 if (!ddb_prioritize_control_input && !db_raw_space())
  442                         return;
  443                 c = cncheckc();
  444                 switch (c) {
  445                 case -1:                /* no character */
  446                         return;
  447 
  448                 case CTRL('c'):
  449                         db_do_interrupt("^C");
  450                         /*NOTREACHED*/
  451 
  452                 case CTRL('s'):
  453                         do {
  454                                 c = cncheckc();
  455                                 if (c == CTRL('c'))
  456                                         db_do_interrupt("^C");
  457                         } while (c != CTRL('q'));
  458                         break;
  459 
  460                 default:
  461                         if (db_raw_space()) {
  462                                 db_raw_push(c);
  463                         } else if (!db_raw_warned) {
  464                                 db_raw_warned = 1;
  465                                 db_printf("\n--Exceeded input buffer--\n");
  466                         }
  467                         break;
  468                 }
  469         }
  470 }

Cache object: c695592d7b3ca5db63c48bc4b9cc9b15


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