home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1741 / cled.c.2
Text File  |  1990-12-28  |  37KB  |  1,786 lines

  1.     {
  2.     int                     ospl;
  3.  
  4.     ospl = spl6();
  5.     {
  6.         last = next->last;
  7.         (tbp->last = last)->next = (tbp->next = next)->last = tbp;
  8.     }
  9.     splx(ospl);
  10.     }
  11. #endif
  12.  
  13.     tbp->flags = TB_INSERT;
  14.     setup_tcap_defaults(tbp);
  15.     setup_key_defaults(tbp);
  16.  
  17.     tty_used = tbp;
  18.     return tbp;
  19. }
  20.  
  21. /*
  22.     Find a tty_buf that's attached to a tty struct and move it to the head of
  23.     the que if it's in the list.
  24.  
  25.     ENTRY: Process context: task. Must not be called from interrupt. tp -
  26.     ptr to tty struct to match
  27.  
  28.     EXIT: returns ptr to tty_buf or 0 if none found. Does not modify the
  29.     contents of any structures, so it is re-entrant and interruptable.
  30. */
  31.  
  32. static struct tty_buf   *find_ttybuf(tp)
  33.     struct tty              *tp;
  34. {
  35.     register struct tty_buf *tbp;
  36.     int                     cnt = 0;
  37.  
  38.     if (tty_used == 0)
  39.     return 0;
  40.  
  41.     tbp = tty_used;
  42.  
  43.     do
  44.     {
  45.     if (tbp->ttyp == tp)
  46.     {
  47. #if INKERNEL
  48.         if (tbp != tty_used)
  49.         {
  50.         int                     ospl;
  51.  
  52.         ospl = spl6();
  53.         {
  54.             register struct tty_buf *next,*last;
  55.  
  56.             tbp->next->last = tbp->last;
  57.             tbp->last->next = tbp->next;
  58.             next = tty_used;
  59.             last = next->last;
  60.             (tbp->last = last)->next = (tbp->next = next)->last = tbp;
  61.             tty_used = tbp;
  62.         }
  63.         splx(ospl);
  64.         }
  65. #endif /* INKERNEL */
  66.         return tbp;
  67.     }
  68.  
  69.     tbp = tbp->next;
  70.     cnt++;
  71.     }
  72.     while (tbp != tty_used && cnt < cle_ttys);
  73.  
  74.     return 0;
  75. }
  76.  
  77. /*
  78.     The routines cleopen, cleclose, cleread, clewrite and cleioctl are called
  79.     by the kernel (via a dispatch through the linesw array) and are all
  80.     executed at process task time. The routines cleinput and cleouput are
  81.     interrupt routines. Except for cleinput and cleioctl all the routines have
  82.     the same interface: a pointer to the tty struct assigned to the real or
  83.     pseudo terminal. cleinput has an extra flag argument which indicates
  84.     whether the input character is real or the result of the terminal sending
  85.     a break. cleioctl has an extra argument that has the function code the
  86.     ioctl is to do.
  87. */
  88.  
  89. /*
  90.     Send saved broadcast message to terminal.
  91.  
  92.     ENTRY: Process context: task. tbp - ptr to tty_buf which contains the
  93.     message clr_flg - true if the message line is to be precleared
  94.  
  95.     EXIT:  the cblock(s) holding the message are moved from the clist in
  96.     tty_buf to the t_outq clist.
  97. */
  98.  
  99. static void        send_brdcst(tbp,clr_flg)
  100.     struct tty_buf          *tbp;
  101.     int                     clr_flg;
  102. {
  103. #if INKERNEL
  104.     int                     ospl;
  105.     unchar                  c;
  106.     struct cblock           *bp;
  107.     struct clist            *bl,*tpc;
  108.  
  109.     tpc = &tbp->ttyp->t_outq;
  110.     bl = &tbp->broadcast;
  111.     if (clr_flg)
  112.     {
  113.     cle_putc('\r',tbp->ttyp);
  114.         cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
  115.     }
  116.  
  117.     ospl = spl6();
  118.     {
  119.     while ((bp = getcb(bl)) != 0)
  120.         putcb(bp,tpc);
  121.     kick_out(tbp->ttyp);
  122.     }
  123.     splx(ospl);
  124. #endif /* INKERNEL */
  125. }
  126.  
  127. /*
  128.     Open line discpline
  129.  
  130.     ENTRY: tbp - ptr to tty_buf to open (or 0 if not preassigned) td - ptr
  131.     to tty struct  to open
  132. */
  133.  
  134. static struct tty_buf   *open_it(tbp,td)
  135.     register struct tty_buf *tbp;
  136.     struct tty              *td;
  137. {
  138.     int                     wasclosed;
  139.  
  140. #if INKERNEL
  141.     if (tbp != 0)
  142.     wasclosed = !(tbp->flags&TB_OPEN);
  143.     else
  144.     {
  145.     garbage_collect();
  146.     tbp = get_ttybuf(td);
  147.     wasclosed = YES;
  148.     }
  149.  
  150.     if (tbp != 0)
  151.     {
  152.     tbp->flags |= (TB_OPEN|TB_OPENING);
  153.     if (wasclosed)
  154.     {
  155. #if VERBOSE
  156.         show_pid(1," started by process ",td);
  157. #endif
  158.     }
  159.     }
  160.     else
  161.     {
  162.     if (wasclosed)
  163.     {
  164.         cle_puts("\rNo buffers available to start cled\r\n",td);
  165.         u.u_error = ERR_NOTTYBUF;
  166.     }
  167.     }
  168.  
  169.     if (wasclosed)
  170.     kick_out(td);
  171. #endif
  172.  
  173.     return tbp;
  174. }
  175.  
  176. /*
  177.     Open the line discipline. This procedure is called by kernel code when the
  178.     line discipline is selected. I haven't yet determined what exactly the
  179.     open is supposed to do, but since cled uses discipline 0, if IT (ld0)
  180.     isn't opened too, very strange terminal behavior results.
  181.  
  182.     ENTRY: tp - ptr to tty struct process context: task.
  183.  
  184.     EXIT:  discipline 0 is opened.
  185. */
  186.  
  187. cleopen(tp)
  188.     struct tty              *tp;
  189. {
  190. #if INKERNEL
  191.     (*linesw[0].l_open) (tp);
  192.     (void) open_it(find_ttybuf(tp),tp);
  193. #endif
  194.  
  195.     return 1;
  196. }
  197.  
  198. /*
  199.     Close the line discpline
  200.  
  201.     ENTRY: tbp - ptr to tty_buf to close (or 0 if not preassigned) td - ptr
  202.     to tty struct  to open
  203. */
  204.  
  205. static void             close_it(tbp,td)
  206.     struct tty_buf          *tbp;
  207.     struct tty              *td;
  208. {
  209. #if INKERNEL
  210.     if (tbp != 0)
  211.     {
  212.     int                     ospl;
  213.  
  214.     if (td->t_state&ISOPEN)
  215.     {
  216. #if VERBOSE
  217.         show_pid(0,"\rcled stopped by process ",td);
  218. #endif
  219.         kick_out(td);
  220.     }
  221.  
  222.     if (tbp->readsleep)
  223.     {
  224.         wakeup(tbp);
  225.         tbp->readsleep = NO;
  226.         if (td->t_state&ISOPEN)
  227.         tbp->flags |= TB_FLUSHIT;
  228.     }
  229.  
  230.     ospl = spl6();
  231.     {
  232.         tbp->flags &=~ (TB_OPEN|TB_OPENING);
  233.     }
  234.     splx(ospl);
  235.     }
  236.  
  237. #if MULTILB
  238.     free_leds(tbp);
  239. #endif
  240.  
  241. #endif
  242. }
  243.  
  244. /*
  245.     Close the line discipline. This procedure is called by kernel code when
  246.     the line discipline is deselected. I haven't yet determined what exactly
  247.     the close is supposed to do, but a call to close discipline 0 is done
  248.     because it apparently needs it.
  249.  
  250.     ENTRY: tp - ptr to tty struct process context: task.
  251.  
  252.     EXIT:  discipline 0 is closed.
  253. */
  254.  
  255. cleclose(tp)
  256.     struct tty              *tp;
  257. {
  258.     struct tty_buf        *tbp;
  259.  
  260.     tbp = find_ttybuf(tp);
  261.  
  262. #if INKERNEL
  263.     (*tp->t_proc) (tp,T_RESUME);
  264.     close_it(tbp,tp);
  265.     delay(HZ);
  266.     ttyflush(tp,FWRITE|FREAD);
  267.     (*linesw[0].l_close) (tp);
  268. #endif
  269.  
  270.     return 1;
  271. }
  272.  
  273. #if INKERNEL
  274.  
  275. /*
  276.     Input interrupt routine. This routine is called after n characters have
  277.     been placed in the interrupt holding buffer (t_rbuf) and/or a certain
  278.     time has elapsed since the last input interrupt occurred (This technique
  279.     tends to reduce the CPU load somewhat by bunching input character
  280.     processing on dumb terminal ports).
  281.  
  282.     The input routine processes the characters in the device buffer, which
  283.     is an array, and then appends them to the raw queue, which is a clist.
  284.     It wakes up the waiting process, which will eventually call cleread that
  285.     will get the characters from the raw queue, to its internal history, and
  286.     then to the user.
  287.  
  288.     If the line discipline is in raw mode, we check for VINTR and VQUIT and
  289.     send the appropriate signal. Notice that we cannot do this in cleread,
  290.     because cleread is only called when the user reads. We want to be able
  291.     to interrupt even if no read is outstanding.
  292. */
  293.  
  294. cleinput(td,bflg)
  295.     struct tty              *td;
  296.     int                     bflg;
  297. {
  298.     int                     i,indx,ospl;
  299.     unchar            ch,*cp,*msg;
  300.     struct tty_buf          *tbp;
  301.  
  302.     i = 0;
  303.     tbp = tty_used;
  304.  
  305.     if (tbp != 0)
  306.     do
  307.     {
  308.         if (tbp->ttyp == td)
  309.         break;
  310.         tbp = tbp->next;
  311.         ++i;
  312.     }
  313.     while ((tbp != tty_used) && i < cle_ttys);
  314.  
  315.     /*
  316.     If we cannot run, let ldisc 0 sort it out...
  317.     */
  318.  
  319.     if (CLEDOFF(td->t_lflag) || tbp == 0 || tbp->ttyp != td
  320.     || (tbp->ttyp == td && (tbp->flags&TB_NOLINE)))
  321.     {
  322.     (*linesw[0].l_input) (td,bflg);
  323.     return;
  324.     }
  325.  
  326.     /*
  327.     Our input is either a break condition or rbuf.
  328.     */
  329.  
  330.     if (bflg == L_BREAK)
  331.     {
  332.     if (!((td->t_lflag&ISIG) && (td->t_iflag&BRKINT)))
  333.         return;
  334.  
  335.     cp = &ch;
  336.     ch = td->t_cc[VINTR];
  337.     i = 1;
  338.     }
  339.     else
  340.     {
  341.     if (td->t_rbuf.c_ptr == 0 || td->t_rbuf.c_count >= td->t_rbuf.c_size)
  342.         return;
  343.  
  344.     i = td->t_rbuf.c_size - td->t_rbuf.c_count;
  345.     cp = (unchar *) td->t_rbuf.c_ptr;
  346.     td->t_rbuf.c_count = td->t_rbuf.c_size;
  347.     }
  348.  
  349.     /*
  350.     Here we have cp that points at the array of chars to process,
  351.     and i is the number of such characters.
  352.     */
  353.  
  354.     for (i, cp; i > 0; --i, cp++)
  355.     {
  356.     register unchar        c;
  357.     int                     quote;
  358.  
  359.     c = *cp;
  360.  
  361.     if (c == '\0')
  362.         continue;
  363.  
  364.     /*
  365.         The switch character is very special. We cannot even
  366.         escape it.
  367.     */
  368.     if (c == td->t_cc[VSWTCH])
  369.     {
  370.         if ((*td->t_proc) (td,T_SWTCH) != T_SWTCH)
  371.         return;
  372.     }
  373.  
  374.     if (quote = (td->t_state & CLESC))
  375.         td->t_state &=~ CLESC;
  376.  
  377.     if (!quote)
  378.     {
  379.         unchar            quit,intr;
  380.  
  381.         quit = td->t_cc[VQUIT];
  382.         intr = td->t_cc[VINTR];
  383.  
  384.         if (c == quit || c == intr)
  385.         {
  386.         if (!(td->t_lflag&NOFLSH))
  387.             ttyflush(td,FWRITE|FREAD);
  388.  
  389.         kick_out(td);
  390.  
  391.         tbp->lbp->flags |= (c == intr) ? LD_INTR : LD_QUIT;
  392.  
  393.         if (tbp->readsleep)
  394.         {
  395.             tbp->flags |= TB_FLUSHIT;
  396.             tbp->readsleep = NO;
  397.             wakeup(tbp);
  398.         }
  399.  
  400.         signal(td->t_pgrp,(c == intr) ? SIGINT : SIGQUIT);
  401.  
  402.         return;
  403.         }
  404.         else if (!CLEKEY_CHAR(c)
  405.         && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_PURGE)
  406.         {
  407.         ttyflush(td,FREAD);
  408.         if (tbp->readsleep)
  409.         {
  410.             tbp->flags |= TB_FLUSHIT;
  411.             break;
  412.         }
  413.         }
  414.     }
  415.  
  416.     if (td->t_rawq.c_cc > (TTYHOG-3) || putc(c,&td->t_rawq) == -1)
  417.     {
  418.         tbp->flags |= TB_OVERUN;
  419.         cle_putc(BEL,td);
  420.         continue;
  421.     }
  422.  
  423.     if (!quote)
  424.     {
  425.         if (!CLEKEY_CHAR(c) && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_ESCAPE)
  426.         td->t_state |= CLESC;
  427.         else if
  428.         (
  429.         c == td->t_cc[VEOL]
  430.         || c == td->t_cc[VEOL2]
  431.         || c == td->t_cc[VEOF]
  432.         || (!CLEKEY_CHAR(c)
  433.             && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_NEWLINE))
  434.         {
  435.         /* count it so rdchk() works */
  436.         td->t_delct++;
  437.         }
  438.     }
  439.     }
  440.  
  441.     if (tbp->readsleep)
  442.     {
  443.     tbp->readsleep = NO;
  444.     wakeup(tbp);
  445.     }
  446.  
  447. #if M_UNIX
  448.     /*
  449.        if by some chance, we're turned on while LD 0 is reading, wake it up
  450.        too
  451.     */
  452.     if (td->t_state & IASLP)
  453. #if M_ATT
  454.     ttrstrt(td);
  455. #else
  456.     ttiwake(td);
  457. #endif
  458. #endif
  459. }
  460.  
  461. /*
  462.     Output interrupt routine. This routine does nothing at this time. Control
  463.     is passed to discipline 0 for output. It normally just moves text from the
  464.     t_outq clist to the t_obuf output que. Null chars and timers may be set
  465.     appropriately depending on the char being output. This discipline has no
  466.     interest in changing the behaviour of the output routines.
  467.  
  468.     ENTRY: td - ptr to tty struct Process context: Interrupt.
  469.  
  470.     EXIT:  Characters may have been moved from t_outq to t_obuf and the
  471.     output started.
  472. */
  473.  
  474. cleoutput(td)
  475.     struct tty              *td;
  476. {
  477.     return (*linesw[0].l_output) (td);
  478. }
  479.  
  480. /*
  481.     read timeout routine. This is a a kludge cuz I can't figure out who's
  482.     zapping the tty struct out from under cled. It usually happens after the
  483.     cleread routine has gone to sleep. It can be forced, however by some other
  484.     process intentionally changing the line number or other tty flags while a
  485.     read is in progress. This routine helps correct the situation.
  486.  
  487.     ENTRY: arg - ptr to the tty_buf belonging to the process doing the read.
  488.  
  489.     EXIT: TB_TIMEOUT set in the tty flags and a wakeup is delivered.
  490. */
  491.  
  492. static void             read_timeout(arg)
  493.     struct tty_buf          *arg;
  494. {
  495.     if (arg->readsleep)
  496.     wakeup(arg);
  497.     arg->readsleep = NO;
  498. }
  499.  
  500. /*
  501.     Announce that's there's no room at the inn
  502.  
  503.     ENTRY: tp - ptr to tty struct typ - ascii string describing buffer type
  504.     that we're out of
  505.  
  506.     EXIT: message output to the terminal line discipline reset to ld 0.
  507. */
  508.  
  509. static int        no_room(tp,typ)
  510.     struct tty              *tp;
  511.     unchar                  *typ;
  512. {
  513.     cle_puts("\rInsufficient ",tp);
  514.     cle_puts(typ,tp);
  515.     cle_puts(" buffers to run cled at this time.\r",tp);
  516.     tp->t_line = 0;
  517.     (*linesw[0].l_read) (tp);
  518.     return 1;
  519. }
  520.  
  521. #endif /* INKERNEL */
  522.  
  523. /*
  524.     Read a line from the terminal. This routine exits when the user types the
  525.     specified eol character (normally a \r).
  526.  
  527.     ENTRY: Process context: task. tp - ptr to tty struct
  528.  
  529.     EXIT: process sleeps until user types one of an EOL, an EOF, a QUIT or
  530.     an INTR character (normally an \r, ^D, DEL and ^C characters
  531.     respectively). The line of text input from terminal is moved to user's
  532.     buffer as specified by u.u_count and u.u_base. An EOF results in 0
  533.     chars being returned. This routine will not exit normally if an
  534.     interrupt or quit character is typed (the kernel takes control via the
  535.     signal and will cancel the I/O request without this routine going
  536.     through its normal exit sequence). If the terminal has been set to
  537.     "raw" mode, this read passes control to discipline 0, otherwise the
  538.     line editing functions of cled become active while the line of input is
  539.     being typed.
  540. */
  541.  
  542. cleread(tp)
  543.     struct tty              *tp;
  544. {
  545.     struct led_buf          *lb;
  546.     struct tty_buf          *tbp;
  547.     unchar                  *cp;
  548.     int                     c,len,time_id;
  549.  
  550.     tbp = find_ttybuf(tp);
  551.  
  552. #if INKERNEL
  553.     if (tbp == 0)
  554.     return no_room(tp,"tty");
  555.  
  556.     if (u.u_count == 0 || CLEDOFF(tp->t_lflag))
  557.     {
  558.     if (tbp != 0)
  559.         tbp->flags |= TB_NOLINE;
  560.     (*linesw[0].l_read) (tp);
  561.     return 1;
  562.     }
  563.  
  564.     if (!(tbp->flags&TB_OPEN))
  565.     open_it(tbp,tp);
  566. #endif
  567.  
  568. #if !MULTILB
  569.     lb = tbp->lbp;
  570. #else
  571.     lb = find_ledbuf(tbp,u.u_procp);
  572.     if (lb == 0)
  573.     lb = get_ledbuf(tbp);
  574. #endif
  575.  
  576.     if (tbp->broadcast.c_cc != 0)
  577.     {
  578.     send_brdcst(tbp,0);
  579.     cle_putc('\n',tp);
  580.     tbp->dorefresh = YES;
  581.     }
  582.  
  583. #if INKERNEL
  584.     if (lb == 0)
  585.     {
  586.     close_it(tbp,tp);
  587.     return no_room(tp,"led");
  588.     }
  589. #endif
  590.  
  591.     tbp->flags &=~ (TB_NOLINE|TB_OPENING);
  592.  
  593. #if INKERNEL
  594.     if (lb->owed != 0)
  595.     {
  596.     len = lb->lcurs - lb->owed;
  597.  
  598.     if (len > 0)
  599.     {
  600.         if (len > u.u_count)
  601.         len = u.u_count;
  602.         if (copyout(lb->owed,u.u_base,len) < 0)
  603.         {
  604.         u.u_error = EFAULT;
  605.         return 1;
  606.         }
  607.         lb->owed += len;
  608.         u.u_base += len;
  609.         u.u_count -= len;
  610.         if (lb->owed >= lb->lcurs)
  611.         lb->owed = 0;
  612.         return 1;
  613.     }
  614.  
  615.     lb->owed = 0;
  616.     }
  617. #endif
  618.  
  619.     /*
  620.     Initialize command buffer and display to empty line
  621.     */
  622.     lb->current = 0;
  623.     lb->lastchar = sizeof lb->line - 1;
  624.  
  625.     lb->lcurs = lb->line;
  626.     lb->rcurs = lb->lineend = lb->line + lb->lastchar;
  627.     *lb->lcurs = *lb->rcurs = '\0';
  628.  
  629.     lb->state = NORMAL;
  630.  
  631.     /*
  632.     Reset history pointers to bottom
  633.     */
  634.     lb->lastline = 0;
  635.     lb->matchlen = 0;
  636.  
  637.     /*
  638.     Initialize flags
  639.     */
  640.     lb->flags &=~ (LD_DONE|LD_EOF|LD_INTR|LD_QUIT|LD_INSERT);
  641.     lb->flags |= (LD_DIRTY);
  642.     if (tbp->flags&TB_INSERT)
  643.     lb->flags |= LD_INSERT;
  644.     tbp->flags |= TB_READING;
  645.  
  646. #if INKERNEL
  647.     tbp->iflag = tp->t_iflag;
  648.     tbp->oflag = tp->t_oflag;
  649.     tbp->lflag = tp->t_lflag;
  650.     tbp->cflag = tp->t_cflag;
  651.     for (c = 0; c < NCC + 2; c++)
  652.     tbp->cc[c] = tp->t_cc[c];
  653.  
  654.     /*
  655.     Print any pending output
  656.     */
  657.     while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
  658.     {
  659.     kick_out(tp);
  660.     delay(HZ/10);
  661.     }
  662. #endif
  663.  
  664.     while (!(lb->flags&LD_DONE))
  665.     {
  666. #if INKERNEL
  667.     int                     ospl;
  668.  
  669.     ospl = spl6();
  670.     {
  671.         /*
  672.         Wait for input if there is none queued
  673.         */
  674.  
  675.         if (tp->t_rawq.c_cc == 0)
  676.         {
  677.         if (tbp->dorefresh)
  678.         {
  679.             tbp->dorefresh = NO;    
  680.             splx(ospl);
  681.  
  682.             reprint(lb);
  683.             kick_out(tp);
  684.             continue;
  685.         }
  686.  
  687.         if (!(tbp->flags&TB_OPEN))
  688.         {
  689.             lb->flags |= (LD_DONE|LD_EOF);
  690.             msg("Trying to cleread while CLED turned off",lb);
  691.             break;
  692.         }
  693.  
  694.         if (tp->t_line != our_lineno || CLEDOFF(tp->t_lflag))
  695.         {
  696.             tp->t_line = our_lineno;
  697.             tp->t_iflag = tbp->iflag;
  698.             tp->t_oflag = tbp->oflag;
  699.             tp->t_lflag = tbp->lflag;
  700.             tp->t_cflag = tbp->cflag;
  701.             for (c = 0; c < NCC + 2; c++)
  702.             tp->t_cc[c] = tbp->cc[c];
  703.  
  704.             tp->t_state |= ISOPEN;
  705.             tbp->dorefresh = YES;
  706.  
  707.             msg("CLED: tty struct has been zapped. Resetting it.",lb);
  708.             continue;
  709.         }
  710.  
  711.         /*
  712.             Sleep for a while for input to arrive
  713.         */
  714.         time_id = timeout(read_timeout,tbp,HZ*15);
  715.         tbp->readsleep = YES;
  716.  
  717.         if (sleep(tbp,(PZERO+8)|PCATCH))
  718.         {
  719.             ospl = spl6();
  720.             {
  721.             tbp->flags &=~ (TB_FLUSHIT|TB_READING);
  722.             tbp->dorefresh = tbp->readsleep = NO;
  723.             }
  724.             splx(ospl);
  725.  
  726.             untimeout(time_id);
  727.             u.u_error = EINTR;
  728.  
  729.             return -1;
  730.         }
  731.  
  732.         /*
  733.             Alleluiah! We may have gotten something from cleinput
  734.         */
  735.  
  736.         untimeout(time_id);
  737.         splx(ospl);
  738.  
  739.         while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
  740.         {
  741.             kick_out(tp);
  742.             delay(HZ/10);
  743.         }
  744.  
  745.         if (tbp->flags&TB_FLUSHIT)
  746.         {
  747.             bol(lb);
  748.             d_eol(lb);
  749.  
  750.             ospl = spl6();
  751.             {
  752.             tbp->flags &=~ TB_FLUSHIT;
  753.             tbp->dorefresh = tbp->readsleep;
  754.             }
  755.             splx(ospl);
  756.  
  757.             if (!(tbp->flags & TB_OPEN))
  758.             break;
  759.         }
  760.         continue;
  761.         }
  762.     }
  763.     splx(ospl);
  764. #endif /* INKERNEL */
  765.  
  766.     /*
  767.         Get next char from the raw input queue, filled by cleinput
  768.     */
  769.  
  770.     c = cle_getc(tp);
  771.  
  772.     if (c != 0 && lb->state == NORMAL)
  773.     {
  774.         if (c == tp->t_cc[VERASE])
  775.         c = 0, lb->state = (NCC_SPC(VERASE));
  776.         else if (c == tp->t_cc[VKILL])
  777.         c = 0, lb->state = (NCC_SPC(VKILL));
  778.         else if (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
  779.         c = 0, lb->state = (NCC_SPC(VEOL));
  780.         else if (c == tp->t_cc[VEOF])
  781.         c = 0, lb->state = (NCC_SPC(VEOL)), lb->flags = LD_EOF;
  782.     }
  783.  
  784.     lb->c = c;
  785.     parse_it(lb);
  786.  
  787. #if INKERNEL
  788.     kick_out(tp);
  789. #endif
  790.     }
  791.  
  792.     tbp->flags &=~ TB_READING;
  793.  
  794.     cp = lb->lcurs;
  795.     if (!(lb->flags&(LD_EOF/*|LD_INTR|LD_QUIT*/)))
  796.     {
  797.     *cp++ = '\n';
  798.     lb->lcurs = cp;
  799.     }
  800.  
  801.     len = cp - lb->line;
  802.  
  803. #if INKERNEL
  804.     if (len != 0 && !(lb->flags&(LD_INTR|LD_QUIT)))
  805.     {
  806.     if (len > u.u_count)
  807.         len = u.u_count;
  808.     if (copyout(lb->line,u.u_base,len) < 0)
  809.     {
  810.         u.u_error = EFAULT;
  811.         return;
  812.     }
  813.     u.u_base += len;
  814.     u.u_count -= len;
  815.     tp->t_col = 0;
  816.     cle_putc('\r',tp);    /* ICRNL */
  817.     cle_putc('\n',tp);    /* OCRNL */
  818.     }
  819.  
  820.     /* count down the delimiter */
  821.     if (tp->t_delct > 0)
  822.     --tp->t_delct;
  823.  
  824.     if (tbp->broadcast.c_cc != 0)
  825.     {
  826.     send_brdcst(tbp,0);
  827.     cle_putc('\r',tp);
  828.     cle_putc('\n',tp);
  829.     }
  830.  
  831.     kick_out(tp);
  832. #else
  833.     strncpy(u.u_base,lb->line,len);
  834.     *(u.u_base + len) = 0;
  835. #endif /* INKERNEL */
  836.  
  837.     lb->owed = (lb->line + len >= lb->lcurs) ? (unchar *) 0 : lb->line+len;
  838.  
  839.     lb->promptlen = 0;
  840.     lb->prompt[0] = '\0';
  841.  
  842.     return 1;
  843. }
  844.  
  845. #if INKERNEL
  846. /*
  847.     Write some text to the terminal but catch any trailing data into a prompt
  848.     buffer. This routine is executed when no read is in progress on the
  849.     terminal, an lb buffer is assigned to the terminal and a write comes
  850.     through.
  851.  
  852.     ENTRY: tbp - ptr to tty_buf assigned to terminal lb - ptr to
  853.     led_buf assigned to terminal u.u_base - ptr to message
  854.     (u.u_count has length of message)
  855.  
  856.     EXIT: the text from the trailing \n (if any) of the message has been
  857.     copied to the prompt buffer in the led_buf. If the last char of the
  858.     message is a \n, then prompt buffer is left empty. If there are no
  859.     \n's in the message, then the whole message is appended to any
  860.     existing data in the prompt buffer. Chars are removed from the
  861.     beginning of the buffer if the length of the new message exceeds the
  862.     MAXPROMPT parameter.
  863. */
  864.  
  865. static void              catch_prompt(tbp,lb)
  866.     struct tty_buf          *tbp;
  867.     struct led_buf          *lb;
  868. {
  869. #if M_SPTALLOC
  870.     unchar            *prompt;
  871. #else
  872.     unchar            prompt[MAXPROMPT+1];
  873. #endif
  874.     int                maxlen;
  875.     register unchar        *tail,*old;
  876.     register int        headlen;
  877.  
  878.     if (tbp->broadcast.c_cc != 0)
  879.     send_brdcst(tbp,1);
  880.  
  881.     /*
  882.     If the write is zero length, we just return; if the last
  883.     character of the write is a newline, than the write is surely
  884.     not for a prompt; prompts are non NL terminated writes.
  885.     */
  886.  
  887.     {
  888.     unchar           ch;
  889.  
  890.     if (copyin(u.u_base + u.u_count - 1,&ch,sizeof ch) < 0)
  891.         return;
  892.  
  893.     if (ch == '\n')
  894.     {
  895.         lb->promptlen = 0;
  896.         lb->prompt[0] = '\0';
  897.         return;
  898.     }
  899.     }
  900.  
  901. #if M_SPTALLOC
  902.     prompt = (unchar *) Sptalloc(maxlen+1);
  903. #endif
  904.  
  905.     /*
  906.     Fetch the last maxlen characters of the prompt, and null
  907.     terminate them.
  908.     */
  909.     maxlen = MIN(u.u_count,MAXPROMPT); /* This is at least 1 */
  910.     if (copyin(u.u_base + (u.u_count - maxlen),prompt,maxlen) < 0)
  911.     return;
  912.     *(tail = prompt + maxlen) = '\0';
  913.  
  914.     /*
  915.     Determine the real prompt, which is the tail after the last
  916.     '\r' or '\n'. We *know* that maxlen != 0 implies tail > prompt initially.
  917.     */
  918.     do --tail; while (tail > prompt && !(*tail == '\r' || *tail == '\n'));
  919.     if (*tail == '\r' || *tail == '\n') tail++;
  920.  
  921.     /*
  922.         First we assume that the head of the new prompt is empty, then we
  923.         check; if the old prompt was not empty and the new prompt tail did not
  924.         start with '\r' or '\n', and leaves some space in the prompt buffer we
  925.         prepend the tail of the old prompt as the head of the new one,
  926.         shifting it into place if necessary. We expect this to be executed
  927.         very rarely; actually we should probably not bother at all...
  928.     */
  929.  
  930.     old = lb->prompt;
  931.  
  932.     if (tail == prompt && lb->promptlen && !(tbp->flags&TB_WRITING)
  933.     && (headlen = tail-prompt + MAXPROMPT-maxlen) > 0)
  934.     {
  935.     if (headlen >= lb->promptlen)
  936.         old += lb->promptlen;
  937.     else
  938.     {
  939.         bcopy(old+lb->promptlen-headlen,old,headlen);
  940.         old += headlen;
  941.     }
  942.     }
  943.  
  944.     /*
  945.     A simple while will do instead of bcopy; we assume the tail will
  946.     usually be very small, i.e. <= 8 chars.
  947.     */
  948.     while (*old++ = *tail++);
  949.     lb->promptlen = old-1 - lb->prompt;
  950.  
  951. #if M_SPTALLOC
  952.     Sptfree(temp,maxlen+1);
  953. #endif
  954. }
  955.  
  956. /*
  957.     Breakthru. This routine is called when a message is to be sent to the
  958.     terminal while a read is in progress. The message is prefixed with a
  959.     \r<clear_to_eol> to make room on the current line for the new message and
  960.     all text up to and including the last \n is transmitted to the terminal.
  961.     Any text from the last \n to the end of the buffer is saved in the
  962.     broadcast clist which is transmitted either with the next message to be
  963.     written or when the read completes. In any case, the refresh bit is set to
  964.     cause the user's command line to be reprinted after the write completes.
  965.  
  966.     ENTRY: tbp - ptr to tty_buf u.u_base - ptr to message to send to
  967.     terminal.
  968.  
  969.     EXIT: user data is transmitted to the terminal.
  970. */
  971.  
  972. #if BREAKTHRU
  973. static void             breakthru(tbp)
  974.     struct tty_buf          *tbp;
  975. {
  976.     unchar                  last;
  977.     int                     len;
  978.     struct clist            *bcl;
  979.  
  980.     if (copyin(u.u_base + u.u_count - 1,&last,1) < 0)
  981.     return;
  982.  
  983.     bcl = &tbp->broadcast;
  984.  
  985.     if (last == '\n')
  986.     {
  987.     if (bcl->c_cc > 0)
  988.         send_brdcst(tbp,YES);
  989.     else
  990.     {
  991.         cle_putc('\r',tbp->ttyp);
  992.         cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
  993.     }
  994.     tbp->dorefresh = YES;
  995.     }
  996.     else
  997.     {
  998.     int                     len,oldlen;
  999.     unchar                  *src,*dst;
  1000. #if M_SPTALLOC
  1001.     unchar                  *temp;
  1002. #else
  1003.     unchar                  temp[MAXPROMPT];
  1004. #endif
  1005.  
  1006.     len = 132;        /* assume max length */
  1007.     if (len <= u.u_count)
  1008.     {
  1009.         if (bcl->c_cc > 0)
  1010.         send_brdcst(tbp,1);
  1011.     }
  1012.     else
  1013.     {
  1014.         /* user data is smaller than 1 line */
  1015.  
  1016.         /* but would overflow */
  1017.         if (bcl->c_cc + u.u_count > len)
  1018.         {
  1019.         send_brdcst(tbp,1);
  1020.         cle_putc('\r',tbp->ttyp);
  1021.         cle_putc('\n',tbp->ttyp);
  1022.         tbp->dorefresh = YES;
  1023.         }
  1024.  
  1025.         len = u.u_count;
  1026.     }
  1027.  
  1028.     oldlen = len;
  1029.  
  1030. #if M_SPTALLOC
  1031.     temp = (unchar *) Sptalloc(oldlen + 1);
  1032. #endif
  1033.  
  1034.     if (copyin(u.u_base + (u.u_count - len),temp,len) < 0)
  1035.         return;
  1036.  
  1037.     src = temp + len;
  1038.     *src = '\0';
  1039.  
  1040.     for (; len > 0; --len)
  1041.     {
  1042.         unchar                  c;
  1043.  
  1044.         c = *--src;
  1045.         if (c == '\r' || c == '\n')
  1046.         {
  1047.         ++src;
  1048.         break;
  1049.         }
  1050.     }
  1051.  
  1052.     /* compute real length of message */
  1053.     len = oldlen - len;
  1054.     if (bcl->c_cl != 0)
  1055.     {
  1056.         int                     i;
  1057.         struct cblock           *cbkp;
  1058.  
  1059.         cbkp = bcl->c_cl;
  1060.         i = CLSIZE - cbkp->c_last;    /* room in last cblock */
  1061.         if (i > 0)
  1062.         {
  1063.         dst = &cbkp->c_data[cbkp->c_last];
  1064.         if (i > len)
  1065.             i = len;
  1066.         len -= i;
  1067.         u.u_count -= i;
  1068.         bcl->c_cc += i;
  1069.         /* move end ptr */
  1070.         cbkp->c_last += i;
  1071.         while (i-- > 0)
  1072.             *dst++ = *src++;
  1073.         }
  1074.     }
  1075.  
  1076.     if (len > 0)
  1077.     {
  1078.         int                     ospl;
  1079.         struct clist            tcl;
  1080.  
  1081.         /* init our dummy clist */
  1082.         tcl.c_cc = 0;
  1083.         tcl.c_cf = tcl.c_cl = 0;
  1084.         u.u_count -= len;
  1085.  
  1086.         ospl = spl6();
  1087.         {
  1088.         putcbp(&tcl,src,len);
  1089.         }
  1090.         splx(ospl);
  1091.  
  1092.         /* if broadcast is empty */
  1093.         if (bcl->c_cf == 0)
  1094.         bcl->c_cf = tcl.c_cf;
  1095.         else
  1096.         bcl->c_cl->c_next = tcl.c_cf;
  1097.  
  1098.         bcl->c_cc += tcl.c_cc;
  1099.         bcl->c_cl = tcl.c_cl;
  1100.     }
  1101.  
  1102. #if M_SPTALLOC
  1103.     Sptfree(temp,oldlen + 1);
  1104. #endif
  1105.     }
  1106.  
  1107.     kick_out(tbp->ttyp);
  1108. }
  1109. #endif /* BREAKTHRU */
  1110.  
  1111. /*
  1112.     Write some text to the terminal. Writes to the terminal can occur at any
  1113.     time by any suitably privledged process. An attempt is made to determine
  1114.     what writes constitute the output of a "prompt" string. This is done by
  1115.     capturing and remembering in the brodcast clist a copy of the data to
  1116.     write from the last \r or \n in the message to the end of the message.
  1117.     Data that has no \r or \n in it is appended to any existing data in the
  1118.     clist (often processes do single char output to the terminal so its no
  1119.     wonder the system gets slow at times). If a led_buf has been assigned to
  1120.     the process doing the write, then the "prompt" data is placed in the
  1121.     led_buf instead of the broadcast clist. If a read is pending on the
  1122.     terminal when a write is issued, only the data up to and including the
  1123.     last \n is transmitted. The remainder is saved in the broadcast clist. If
  1124.     data ends up being sent to the terminal, then the refresh bit is set and
  1125.     the read process is awakened (which causes broadcast messages to
  1126.     automatically refresh the input line).
  1127.  
  1128.     ENTRY: Process context: task. td - ptr to tty struct
  1129.  
  1130.     EXIT:  Write data sent to the terminal and/or stored in the broadcast
  1131.     clist or led_buf (if one assigned).
  1132. */
  1133.  
  1134. clewrite(td)
  1135.     struct tty              *td;
  1136. {
  1137.     int                ospl;
  1138.     struct led_buf        *lb;
  1139.     struct tty_buf        *tbp;
  1140.  
  1141.     if (CLEDOFF(td->t_lflag))
  1142.     {
  1143.     (*linesw[0].l_write)(td);
  1144.     return;
  1145.     }
  1146.  
  1147.     tbp = find_ttybuf(td);
  1148.     if (tbp != 0)
  1149.     {
  1150. #if BREAKTHRU
  1151.     if (tbp->flags&TB_READING)
  1152.         breakthru(tbp);
  1153.     else
  1154. #else
  1155.     if (!(tbp->flags&TB_READING))
  1156. #endif
  1157.     {
  1158. #if !MULTILB
  1159.         lb = tbp->lbp;
  1160.         if (u.u_count > 0)
  1161.         catch_prompt(tbp,lb);
  1162. #else
  1163.         lb = find_ledbuf(tbp,u.u_procp);
  1164.         if (lb != 0)
  1165.         {
  1166.         if (u.u_count > 0)
  1167.             catch_prompt(tbp,lb);
  1168.         }
  1169.         else
  1170.         {
  1171.         if (tbp->broadcast.c_cc > 0)
  1172.             send_brdcst(tbp,0);
  1173.         }
  1174. #endif
  1175.     }
  1176.     tbp->flags |= TB_WRITING;
  1177.     }
  1178.  
  1179.     if (u.u_count > 0)
  1180.         (*linesw[0].l_write)(td);
  1181.     else    kick_out(td);
  1182.  
  1183.     if (tbp != 0)
  1184.     {
  1185.     tbp->flags &=~ TB_WRITING;
  1186.  
  1187.     ospl = spl6();
  1188.     {
  1189.         if (tbp->dorefresh && tbp->readsleep)
  1190.         {
  1191.         tbp->readsleep = NO;
  1192.         wakeup(tbp);
  1193.         }
  1194.     }
  1195.     splx(ospl);
  1196.     }
  1197. }
  1198.  
  1199. #if VERBOSE
  1200. static void             show_pid(disp,str,td)
  1201.     int                     disp;
  1202.     unchar                  *str;
  1203.     struct tty              *td;
  1204. {
  1205.     unchar                  tmp[10],*s;
  1206.  
  1207.     if (disp != 0)
  1208.     {
  1209.     cle_puts("\rcled version ",td);
  1210.     cle_puts(VERSION,td);
  1211.     cle_putc('.',td);
  1212.     s = itoa(PATCHLEVEL,tmp,10); *s = '\0'; cle_puts(s,td);
  1213.     cle_putc(' ',td);
  1214.     }
  1215.     cle_puts(str,td);
  1216.     s = itoa(u.u_procp->p_pid,tmp,10); *s = '\0'; cle_puts(tmp,td);
  1217.     cle_puts(" (",td);
  1218.     s = itoa(u.u_procp->p_ppid,tmp,10); *s = '\0'; cle_puts(tmp,td);
  1219.     cle_puts(")\r\n",td);
  1220.     return;
  1221. }
  1222. #endif /* VERBOSE */
  1223.  
  1224. /*
  1225.     Line discipline IOCTL routine.
  1226.  
  1227.     ENTRY: Process context: task. td - ptr to tty struct f1 - function to
  1228.     perform
  1229.  
  1230.     EXIT: ioctl function is performed
  1231. */
  1232.  
  1233. cleioctl(td,f1,arg,mode)
  1234.     struct tty              *td;
  1235.     int                     f1,mode;
  1236.     faddr_t                 arg;
  1237. {
  1238.     struct tty_buf          *tbp;
  1239.     struct led_buf          *lb;
  1240.  
  1241.     tbp = find_ttybuf(td);
  1242.     if (tbp != 0
  1243.     && ((tbp->flags&(TB_READING|TB_WRITING)) || !tbp->readsleep))
  1244.     {
  1245. #if VERBOSE
  1246.     cle_puts("CLED: ioctl issued while terminal busy. stty bits may be zapped",tbp->tbp);
  1247. #endif
  1248.     kick_out(td);
  1249.     }
  1250.  
  1251.     if (f1 < LDGETCOLS)
  1252.     {
  1253.     if (f1 == LDCLOSE)
  1254.         close_it(tbp,td);
  1255.     else if (f1 == LDOPEN || f1 == LDCHG)
  1256.         open_it(tbp,td);
  1257.     (*linesw[0].l_ioctl) (td,f1,arg,mode);
  1258.     kick_out(td);
  1259.     return;
  1260.     }
  1261.  
  1262. #if CLEDIO
  1263.     
  1264.     garbage_collect(tbp);
  1265.  
  1266.     if (tbp == 0)
  1267.     tbp = get_ttybuf(td);
  1268.  
  1269.     if (tbp == 0)
  1270.     {
  1271.     u.u_error = ERR_NOTTYBUF;
  1272.     return;
  1273.     }
  1274.  
  1275. #if MULTILB
  1276.     if ((lb = tbp->lbp) != 0)
  1277.     {
  1278.     struct led_buf          *us = 0,*parent = 0;
  1279.  
  1280.     do
  1281.     {
  1282.         if (u.u_procp->p_ppid == lb->pid)   parent = lb;
  1283.         if (u.u_procp->p_pid == lb->pid)    us = lb;
  1284.     }
  1285.     while ((lb = lb->next) != tbp->lbp);
  1286.  
  1287.     lb = (us != 0) ? us : (parent != 0) ? parent : 0;
  1288.     }
  1289. #else
  1290.     lb = tbp->lbp;
  1291. #endif
  1292.  
  1293.     switch (f1)
  1294.     {
  1295.     case LDGETCOLS:
  1296.     if (copyout(&tbp->cols,arg,sizeof tbp->cols) < 0)
  1297.     {
  1298.         u.u_error = EFAULT;
  1299.         return;
  1300.     }
  1301.     break;
  1302.  
  1303.     case LDSETCOLS:
  1304.     {
  1305.     int                cols;
  1306.  
  1307.     if (copyin(arg,&cols,sizeof cols) < 0)
  1308.     {
  1309.         u.u_error = EFAULT;
  1310.         return;
  1311.     }
  1312.     setcols(tbp,cols);
  1313.     }
  1314.     break;
  1315.  
  1316.     case LDGETBF:
  1317.     {
  1318.     struct set_key          sk;
  1319.     char                    cnt,len;
  1320.     faddr_t                 outp;
  1321.  
  1322.     sk.modes = 0;
  1323.     sk.modes |= (tbp->flags&TB_INSERT) ? CLEMODE_INSERT : CLEMODE_OVER;
  1324.     sk.kdbuf_len = CLEKEY_MAX;
  1325.  
  1326.     if (copyout(tbp->keymap,arg + sizeof (sk),CLEKEY_MAX) < 0)
  1327.     {
  1328.         u.u_error = EFAULT;
  1329.         return;
  1330.     }
  1331.     outp = arg + sizeof (sk) + CLEKEY_MAX;
  1332.  
  1333.     for (cnt = 0; cnt < TCAP_COUNT; ++cnt)
  1334.     {
  1335.         unchar                  *s;
  1336.  
  1337.         if (copyout(&cnt,outp++,1) < 0)
  1338.         {
  1339.         u.u_error = EFAULT;
  1340.         return;
  1341.         }
  1342.         s = (unchar *) tbp->tcap[cnt];
  1343.         while (*s++);
  1344.  
  1345.         len = s - (unchar *) tbp->tcap[cnt];
  1346.         if (copyout(tbp->tcap[cnt],outp,len) < 0)
  1347.         {
  1348.         u.u_error = EFAULT;
  1349.         return;
  1350.         }
  1351.         outp += len;
  1352.     }
  1353.  
  1354.     sk.tcapbuf_len = outp - (arg + sizeof (sk) + CLEKEY_MAX);
  1355.     if (copyout(&sk,arg,sizeof (sk)) < 0)
  1356.     {
  1357.         u.u_error = EFAULT;
  1358.         return;
  1359.     }
  1360.     }
  1361.     break;
  1362.  
  1363.     case LDSETBF:
  1364.     {
  1365.     struct set_key          sk;
  1366.     int                     oldflag;
  1367.  
  1368.     if (copyin(arg,&sk,sizeof (sk)) < 0)
  1369.     {
  1370.         u.u_error = EFAULT;
  1371.         return;
  1372.     }
  1373.     oldflag = tbp->flags;
  1374.     if (sk.modes & CLEMODE_INSERT)    tbp->flags |= TB_INSERT;
  1375.     else if (sk.modes & CLEMODE_OVER)    tbp->flags &= ~TB_INSERT;
  1376.  
  1377.     if (sk.kdbuf_len > CLEKEY_MAX)
  1378.     {
  1379.         sk.kdbuf_len = CLEKEY_MAX;
  1380.         if (copyout(&sk,arg,sizeof (sk)) < 0)
  1381.         {
  1382.         u.u_error = EFAULT;
  1383.         return;
  1384.         }
  1385.         u.u_error = ERR_BADPARAM;
  1386.         return;
  1387.     }
  1388.  
  1389.     if (sk.kdbuf_len > 0)
  1390.     {
  1391. #if M_SPTALLOC
  1392.         unchar                  *tmp,*kp;
  1393. #else
  1394.         unchar                  tmp[100],*kp;
  1395. #endif
  1396.         int                     cnt,size;
  1397.  
  1398.         size = sk.kdbuf_len * 2;
  1399. #if M_SPTALLOC
  1400.         kp = tmp = (unchar *) Sptalloc(size);
  1401. #else
  1402.         if (size > sizeof (tmp))
  1403.         {
  1404.         u.u_error = ERR_BADPARAM;
  1405.         return;
  1406.         }
  1407.         kp = tmp;
  1408. #endif
  1409.  
  1410.         if (copyin(arg + sizeof (sk),tmp,size) < 0)
  1411.         {
  1412.         u.u_error = EFAULT;
  1413.         return;
  1414.         }
  1415.         for (cnt = 0; cnt < sk.kdbuf_len; ++cnt)
  1416.         {
  1417.         int                     key,func;
  1418.  
  1419.         key = *kp++;
  1420.         func = *kp++;
  1421.         if (key >= CLEKEY_MAX || func >= CLEFUN_MAX)
  1422.         {
  1423. #if M_SPTALLOC
  1424.             Sptfree(tmp,size);
  1425. #endif
  1426.             sk.kdbuf_len = cnt;
  1427.             copyout(&sk,arg,sizeof (sk));
  1428.             u.u_error = ERR_BADPARAM;
  1429.             return;
  1430.         }
  1431.         tbp->keymap[CLEKEY_CMD(key)] = func;
  1432.         }
  1433. #if M_SPTALLOC
  1434.         Sptfree(tmp,size);
  1435. #endif
  1436.     }
  1437.  
  1438.     if (sk.tcapbuf_len > 0)
  1439.     {
  1440.         setup_tcap_defaults(tbp);
  1441.         if (sk.tcapbuf_len > 1)
  1442.         {
  1443.         unchar                  *s;
  1444.         int                     nfg = 0;
  1445. #if M_SPTALLOC
  1446.         s = tbp->tcstrings = (unchar *) Sptalloc(sk.tcapbuf_len);
  1447. #else
  1448.         s = tbp->tcstrings;
  1449.         if (sk.tcapbuf_len > TCAP_SIZE)
  1450.         {
  1451.             sk.tcapbuf_len = TCAP_SIZE;
  1452.             copyout(&sk,arg,sizeof (sk));
  1453.             u.u_error = ERR_BADPARAM;
  1454.             return;
  1455.         }
  1456. #endif
  1457.         tbp->tclen = sk.tcapbuf_len;
  1458.         if (copyin(arg + sizeof (sk) + sk.kdbuf_len*2,s,tbp->tclen) < 0)
  1459.         {
  1460.             u.u_error = EFAULT;
  1461.             return;
  1462.         }
  1463.         while (s < tbp->tcstrings + tbp->tclen)
  1464.         {
  1465.             unchar                  *ap;
  1466.             int                     str;
  1467.  
  1468.             str = *s++;
  1469.             if (str >= TCAP_COUNT)
  1470.             {
  1471.             nfg = 1;
  1472.             break;
  1473.             }
  1474.             ap = s;
  1475.             while (*ap && ap < tbp->tcstrings + tbp->tclen)
  1476.             ++ap;
  1477.             if (*ap != 0)
  1478.             {
  1479.             nfg = 1;
  1480.             break;
  1481.             }
  1482.  
  1483.             tbp->tcap[str] = (char *) s;
  1484.             s = ap + 1;
  1485.         }
  1486.         if (nfg)
  1487.         {
  1488.             sk.tcapbuf_len = s - tbp->tcstrings;
  1489.             copyout(&sk,arg,sizeof (sk));
  1490.             u.u_error = ERR_BADPARAM;
  1491.             return;
  1492.         }
  1493.         }
  1494.     }
  1495.     }
  1496.     break;
  1497.  
  1498.     case LDGETHB:
  1499.     if (lb == 0)
  1500.     {
  1501.         u.u_error = ERR_NOLBASS;
  1502.         return;
  1503.     }
  1504.  
  1505.     if (copyout(lb->history,arg,MAXHISTORY) < 0)
  1506.     {
  1507.         u.u_error = EFAULT;
  1508.         return;
  1509.     }
  1510.     break;
  1511.  
  1512.     default:
  1513.     u.u_error = ERR_BADIOCTL;
  1514.     }
  1515. #endif /* CLEDIO */
  1516. }
  1517.  
  1518. /*
  1519.     Device driver entry points; used for backdoor setup of CLED.
  1520. */
  1521.  
  1522. cledinit(dev)
  1523.     int                     dev;
  1524. {
  1525.     int                     cnt;
  1526.  
  1527.     for (cnt = 0; cnt < linecnt; ++cnt)
  1528.     if (linesw[cnt].l_open == cleopen)
  1529.         break;
  1530.  
  1531.     if (cnt < linecnt)
  1532.     {
  1533.     our_lineno = cnt;
  1534.     printf("CLED %s PL%d is ldisc %d.\n",VERSION,PATCHLEVEL,cnt);
  1535.     garbage_collect((struct tty_buf *) 0);
  1536.     }
  1537.     else
  1538.     {
  1539. #if M_UNIX
  1540.     cmn_err(CE_WARN,"CLED %s not in linesw table. Not installed",VERSION);
  1541. #else
  1542.     printf("CLED %s not in linesw table. Not installed.\n",VERSION);
  1543. #endif
  1544.     }
  1545.     return;
  1546. }
  1547.  
  1548. cledioctl(dev,cmd,arg,mode)
  1549.     int                     dev,cmd,mode;
  1550.     faddr_t                 arg;
  1551. {
  1552.     switch (cmd)
  1553.     {
  1554.  
  1555. #if CLEDIO
  1556.     case LDGETS:
  1557.     {
  1558.     int                     cnt;
  1559.     unchar                  *s;
  1560.     struct led_buf          *lb;
  1561.     struct tty_buf          *tbp;
  1562.     struct cle_stats        sts;
  1563.  
  1564.     sts.line    = our_lineno;
  1565.     sts.ledbufs    = cle_leds;
  1566.     sts.ttybufs    = cle_ttys;
  1567.     sts.promptsize    = MAXPROMPT;
  1568.     sts.linesize    = MAXLINE;
  1569.     sts.histsize    = MAXHISTORY;
  1570.     sts.multi_lb    = MULTILB;
  1571.     sts.spt        = M_SPTALLOC;
  1572. #if M_SPTALLOC
  1573.     sts.tcapsize    = 256;
  1574. #else
  1575.     sts.tcapsize    = TCAP_SIZE;
  1576. #endif
  1577.  
  1578.     s = (unchar *) VERSION;
  1579.     for (cnt = 0; cnt < 4; ++cnt)
  1580.     {
  1581.         if ((sts.vers[cnt] = *s++) == 0)
  1582.         break;
  1583.     }
  1584.  
  1585.     tbp = tty_free;
  1586.     cnt = 0;
  1587.     if (tbp != 0)
  1588.     {
  1589.         do
  1590.         {
  1591.         tbp = tbp->next;
  1592.         ++cnt;
  1593.         } while (tbp != tty_free && cnt < cle_ttys);
  1594.     }
  1595.     sts.ttybufs_used = cle_ttys - cnt;
  1596.  
  1597. #if !MULTILB
  1598.     sts.ledbufs_used = sts.ttybufs_used;
  1599. #else
  1600.     cnt = 0;
  1601.     lb = ldb_free;
  1602.     if (lb != 0)
  1603.     {
  1604.         do
  1605.         {
  1606.         lb = lb->next;
  1607.         ++cnt;
  1608.         }
  1609.         while (lb != ldb_free && cnt < cle_leds);
  1610.     }
  1611.  
  1612.     sts.ledbufs_used = cle_leds - cnt;
  1613. #endif
  1614.  
  1615.     if (copyout(&sts,arg,sizeof (struct cle_stats)) < 0)
  1616.     {
  1617.         u.u_error = EFAULT;
  1618.         return;
  1619.     }
  1620.     }
  1621.     break;
  1622. #endif /* CLEDIO */
  1623.  
  1624. #if DEBUG
  1625.     case LDGETB:
  1626.     {
  1627.     struct cle_buf          bfs;
  1628.  
  1629.     bfs.lbsize = cle_leds * sizeof (struct led_buf);
  1630.     bfs.tbsize = cle_ttys * sizeof (struct tty_buf);
  1631.  
  1632.     bfs.lbbase = cle_buffers;
  1633. #if MULTILB
  1634.     bfs.lbfree = ldb_free;
  1635. #else
  1636.     bfs.lbfree = 0;
  1637. #endif
  1638.  
  1639.     bfs.tbbase = cle_ttybuf;
  1640.     bfs.tbused = tty_used;
  1641.     bfs.tbfree = tty_free;
  1642.  
  1643.     bfs.procbase = proc;
  1644.  
  1645.     if (copyout(&bfs,arg,sizeof (struct cle_buf)) < 0)
  1646.     {
  1647.         u.u_error = EFAULT;
  1648.         return;
  1649.     }
  1650.     arg += sizeof (struct cle_buf);
  1651.  
  1652.     if (copyout(cle_buffers,arg,bfs.lbsize) < 0)
  1653.     {
  1654.         u.u_error = EFAULT;
  1655.         return;
  1656.     }
  1657.     arg += bfs.lbsize;
  1658.  
  1659.     if (copyout(cle_ttybuf,arg,bfs.tbsize) < 0)
  1660.     {
  1661.         u.u_error = EFAULT;
  1662.         return;
  1663.     }
  1664.     }
  1665.     break;
  1666.  
  1667.     case LDGETTTY:
  1668.     {
  1669.     struct tty              *ttyp;
  1670.  
  1671.     if (copyin(arg,&ttyp,sizeof (ttyp)) < 0
  1672.         || copyout(ttyp,arg,sizeof (struct tty)) < 0)
  1673.     {
  1674.         u.u_error = EFAULT;
  1675.         return;
  1676.     }
  1677.     }
  1678.     break;
  1679.  
  1680.     case LDGETC:
  1681.     {
  1682.     struct clist            *clp;
  1683.     struct cblock           *cbp;
  1684.     int                     cnt;
  1685.  
  1686.     if (copyin(arg,&clp,sizeof (clp)) < 0)
  1687.     {
  1688.         u.u_error = EFAULT;
  1689.         return;
  1690.     }
  1691.     if (clp->c_cc != 0)
  1692.     {
  1693.         int                     ospl;
  1694.  
  1695.         ospl = spl6();
  1696.         {
  1697.         cbp = clp->c_cf;
  1698.         do
  1699.         {
  1700.             unchar                  siz;
  1701.  
  1702.             siz = cbp->c_last - cbp->c_first;
  1703.             if (siz != 0)
  1704.             {
  1705.             if (copyout(&siz,arg,1) < 0)
  1706.             {
  1707.                 u.u_error = EFAULT;
  1708.                 return;
  1709.             }
  1710.             ++arg;
  1711.             if (copyout(&cbp->c_data[cbp->c_first],arg,siz) < 0)
  1712.             {
  1713.                 u.u_error = EFAULT;
  1714.                 return;
  1715.             }
  1716.             arg += siz;
  1717.             }
  1718.             cbp = cbp->c_next;
  1719.         } while (cbp != 0);
  1720.         }
  1721.         splx(ospl);
  1722.     }
  1723.  
  1724.     cnt = 0;
  1725.     if (copyout(&cnt,arg,1) < 0)
  1726.     {
  1727.         u.u_error = EFAULT;
  1728.         return;
  1729.     }
  1730.     }
  1731.     break;
  1732. #endif /* M_DEBUG */
  1733.     default:
  1734.     u.u_error = ERR_BADIOCTL;
  1735.     }
  1736. }
  1737.  
  1738. #else /* INKERNEL */
  1739.  
  1740. static unchar           cmd_line[256];
  1741. static struct tty       dum_tty;
  1742.  
  1743. struct termio           ostate;    /* saved tty state */
  1744. struct termio           nstate;    /* values for editor mode */
  1745.  
  1746. main()
  1747. {
  1748.     int                     c;
  1749.  
  1750.     dum_tty.t_cc[VINTR]        = 'C' & 0x1f;
  1751.     dum_tty.t_cc[VQUIT]        = '\\' & 0x1f;
  1752.     dum_tty.t_cc[VERASE]    = RUB;
  1753.     dum_tty.t_cc[VKILL]        = 'U' & 0x1f;
  1754.     dum_tty.t_cc[VEOF]        = 'D' & 0x1f;
  1755.     dum_tty.t_cc[VEOL]        = 'M' & 0x1f;
  1756.  
  1757.     ioctl(0,TCGETA,&ostate);
  1758.     ioctl(0,TCGETA,&nstate);
  1759.  
  1760.     nstate.c_iflag    = 0;
  1761.     nstate.c_oflag    = 0;
  1762.     nstate.c_lflag    = 0;
  1763.     nstate.c_cc[VEOF]    = 1;
  1764.     nstate.c_cc[VEOL]    = 0;
  1765.  
  1766.     ioctl(0,TCSETA,&nstate);
  1767.  
  1768.     u.u_base    = cmd_line;
  1769.     u.u_count    = sizeof (cmd_line);
  1770.  
  1771.     garbage_collect((struct tty_buf *) 0);
  1772.  
  1773.     tty_used    = cle_ttybuf;
  1774.     get_ttybuf(&dum_tty);
  1775.  
  1776.     cle_puts("Outputting controls\r\n",&dum_tty);
  1777.  
  1778.     while (cleread(&dum_tty) && strlen(cmd_line))
  1779.     fprintf(stderr,"\r\nRead %d chars\r\n",strlen(cmd_line));
  1780.  
  1781.     ioctl(0,TCSETA,&ostate);
  1782.     return;
  1783. }
  1784.  
  1785. #endif /* INKERNEL */
  1786.