1#! /bin/sh
2# sh tty.sh tty.c
3# This inserts all the needed #ifdefs for IF{} statements
4# and generates tty.c
5
6#
7# Stupid cpp on A/UX barfs on ``#if defined(FOO) && FOO < 17'' when 
8# FOO is undefined. Reported by Robert C. Tindall (rtindall@uidaho.edu)
9#
10rm -f $1
11sed -e '1,26d' \
12-e 's%^IF{\([^}]*\)}\(.*\)%#if defined(\1)\
13\2\
14#endif /* \1 */%' \
15-e 's%^IFN{\([^}]*\)}\(.*\)%#if !defined(\1)\
16\2\
17#endif /* \1 */%' \
18-e 's%^XIF{\([^}]*\)}\(.*\)%#if defined(\1)\
19#if (\1 < MAXCC)\
20\2\
21#endif \
22#endif /* \1 */%' \
23 < $0 > $1
24chmod -w $1
25exit 0
26
27/* Copyright (c) 1993-2002
28 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
29 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
30 * Copyright (c) 1987 Oliver Laumann
31 *
32 * This program is free software; you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation; either version 2, or (at your option)
35 * any later version.
36 *  
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40 * GNU General Public License for more details.
41 *
42 * You should have received a copy of the GNU General Public License
43 * along with this program (see the file COPYING); if not, write to the
44 * Free Software Foundation, Inc.,
45 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
46 *
47 ****************************************************************
48 */
49
50/*
51 * NOTICE: tty.c is automatically generated from tty.sh
52 * Do not change anything here. If you then change tty.sh.
53 */
54
55#include <sys/types.h>
56#include <signal.h>
57#include <fcntl.h>
58#ifndef sgi
59# include <sys/file.h>
60#endif
61#if !defined(sun) || defined(SUNOS3)
62# include <sys/ioctl.h> /* collosions with termios.h */
63#else
64# ifndef TIOCEXCL
65#  include <sys/ttold.h>	/* needed for TIOCEXCL */
66# endif
67#endif
68#ifdef __hpux
69# include <sys/modem.h>
70#endif
71
72#ifdef ISC
73# include <sys/tty.h>
74# include <sys/sioctl.h>
75# include <sys/pty.h>
76#endif
77
78#include "config.h"
79#ifdef SVR4
80#include <sys/stropts.h>	/* for I_POP */
81#endif
82
83#include "screen.h"
84#include "extern.h"
85
86#if !defined(TIOCCONS) && defined(sun) && defined(SVR4)
87# include <sys/strredir.h>
88#endif
89
90extern struct display *display, *displays;
91extern int iflag;
92#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
93extern struct win *console_window;
94static void consredir_readev_fn __P((struct event *, char *));
95#endif
96
97int separate_sids = 1;
98
99static void DoSendBreak __P((int, int, int));
100static sigret_t SigAlrmDummy __P(SIGPROTOARG);
101
102
103/* Frank Schulz (fschulz@pyramid.com):
104 * I have no idea why VSTART is not defined and my fix is probably not
105 * the cleanest, but it works.
106 */
107#if !defined(VSTART) && defined(_VSTART)
108#define VSTART _VSTART
109#endif
110#if !defined(VSTOP) && defined(_VSTOP)
111#define VSTOP _VSTOP
112#endif
113
114#ifndef O_NOCTTY
115# define O_NOCTTY 0
116#endif
117
118#ifndef TTYVMIN
119# define TTYVMIN 1
120#endif
121#ifndef TTYVTIME
122#define TTYVTIME 0
123#endif
124
125
126static sigret_t
127SigAlrmDummy SIGDEFARG
128{
129  debug("SigAlrmDummy()\n");
130  SIGRETURN;
131}
132
133/*
134 *  Carefully open a charcter device. Not used to open display ttys.
135 *  The second parameter is parsed for a few stty style options.
136 */
137
138int
139OpenTTY(line, opt)
140char *line, *opt;
141{
142  int f;
143  struct mode Mode;
144  sigret_t (*sigalrm)__P(SIGPROTOARG);
145
146  sigalrm = signal(SIGALRM, SigAlrmDummy);
147  alarm(2);
148
149  /* this open only succeeds, if real uid is allowed */
150  if ((f = secopen(line, O_RDWR | O_NONBLOCK | O_NOCTTY, 0)) == -1)
151    {
152      if (errno == EINTR)
153        Msg(0, "Cannot open line '%s' for R/W: open() blocked, aborted.", line);
154      else
155        Msg(errno, "Cannot open line '%s' for R/W", line);
156      alarm(0);
157      signal(SIGALRM, sigalrm);
158      return -1;
159    }
160  if (!isatty(f))
161    {
162      Msg(0, "'%s' is not a tty", line);
163      alarm(0);
164      signal(SIGALRM, sigalrm);
165      close(f);
166      return -1;
167    }
168#if defined(I_POP) && defined(POP_TTYMODULES)
169  debug("OpenTTY I_POP\n");
170  while (ioctl(f, I_POP, (char *)0) >= 0)
171    ;
172#endif
173  /*
174   * We come here exclusively. This is to stop all kermit and cu type things
175   * accessing the same tty line.
176   * Perhaps we should better create a lock in some /usr/spool/locks directory?
177   */
178#ifdef TIOCEXCL
179 errno = 0;
180 if (ioctl(f, TIOCEXCL, (char *) 0) < 0)
181   Msg(errno, "%s: ioctl TIOCEXCL failed", line);
182 debug3("%d %d %d\n", getuid(), geteuid(), getpid());
183 debug2("%s TIOCEXCL errno %d\n", line, errno);
184#endif  /* TIOCEXCL */
185  /*
186   * We create a sane tty mode. We do not copy things from the display tty
187   */
188#if WE_REALLY_WANT_TO_COPY_THE_TTY_MODE
189  if (display)
190    {
191      debug1("OpenTTY: using mode of display for %s\n", line);
192      Mode = D_NewMode;
193    }
194  else
195#endif
196    InitTTY(&Mode, W_TYPE_PLAIN);
197  
198  SttyMode(&Mode, opt);
199#ifdef DEBUG
200  DebugTTY(&Mode);
201#endif
202  SetTTY(f, &Mode);
203
204#if defined(linux) && defined(TIOCMSET)
205  {
206    int mcs = 0;
207    ioctl(f, TIOCMGET, &mcs);
208    mcs |= TIOCM_RTS;
209    ioctl(f, TIOCMSET, &mcs);
210  }
211#endif
212
213  brktty(f);
214  alarm(0);
215  signal(SIGALRM, sigalrm);
216  debug2("'%s' CONNECT fd=%d.\n", line, f);
217  return f;
218}
219
220
221/*
222 *  Tty mode handling
223 */
224
225void
226InitTTY(m, ttyflag)
227struct mode *m;
228int ttyflag;
229{
230  bzero((char *)m, sizeof(*m));
231#ifdef POSIX
232  /* struct termios tio 
233   * defaults, as seen on SunOS 4.1.3
234   */
235  debug1("InitTTY: POSIX: termios defaults based on SunOS 4.1.3, but better (%d)\n", ttyflag);
236IF{BRKINT}	m->tio.c_iflag |= BRKINT;
237IF{IGNPAR}	m->tio.c_iflag |= IGNPAR;
238/* IF{ISTRIP}	m->tio.c_iflag |= ISTRIP;  may be needed, let's try. jw. */
239IF{IXON}	m->tio.c_iflag |= IXON;
240/* IF{IMAXBEL}	m->tio.c_iflag |= IMAXBEL; sorry, this one is ridiculus. jw */
241
242  if (!ttyflag)	/* may not even be good for ptys.. */
243    {
244IF{ICRNL}	m->tio.c_iflag |= ICRNL;
245IF{ONLCR}	m->tio.c_oflag |= ONLCR; 
246IF{TAB3}	m->tio.c_oflag |= TAB3; 
247IF{OXTABS}      m->tio.c_oflag |= OXTABS;
248/* IF{PARENB}	m->tio.c_cflag |= PARENB;	nah! jw. */
249IF{OPOST}	m->tio.c_oflag |= OPOST;
250    }
251
252
253/*
254 * Or-ing the speed into c_cflags is dangerous.
255 * It breaks on bsdi, where c_ispeed and c_ospeed are extra longs.
256 *
257 * IF{B9600}    m->tio.c_cflag |= B9600;
258 * IF{IBSHIFT) && defined(B9600}        m->tio.c_cflag |= B9600 << IBSHIFT;
259 *
260 * We hope that we have the posix calls to do it right:
261 * If these are not available you might try the above.
262 */
263IF{B9600}       cfsetospeed(&m->tio, B9600);
264IF{B9600}       cfsetispeed(&m->tio, B9600);
265
266IF{CS8} 	m->tio.c_cflag |= CS8;
267IF{CREAD}	m->tio.c_cflag |= CREAD;
268IF{CLOCAL}	m->tio.c_cflag |= CLOCAL;
269
270IF{ECHOCTL}	m->tio.c_lflag |= ECHOCTL;
271IF{ECHOKE}	m->tio.c_lflag |= ECHOKE;
272
273  if (!ttyflag)
274    {
275IF{ISIG}	m->tio.c_lflag |= ISIG;
276IF{ICANON}	m->tio.c_lflag |= ICANON;
277IF{ECHO}	m->tio.c_lflag |= ECHO;
278    }
279IF{ECHOE}	m->tio.c_lflag |= ECHOE;
280IF{ECHOK}	m->tio.c_lflag |= ECHOK;
281IF{IEXTEN}	m->tio.c_lflag |= IEXTEN;
282
283XIF{VINTR}	m->tio.c_cc[VINTR]    = Ctrl('C');
284XIF{VQUIT}	m->tio.c_cc[VQUIT]    = Ctrl('\\');
285XIF{VERASE}	m->tio.c_cc[VERASE]   = 0x7f; /* DEL */
286XIF{VKILL}	m->tio.c_cc[VKILL]    = Ctrl('H');
287XIF{VEOF}	m->tio.c_cc[VEOF]     = Ctrl('D');
288XIF{VEOL}	m->tio.c_cc[VEOL]     = 0000;
289XIF{VEOL2}	m->tio.c_cc[VEOL2]    = 0000;
290XIF{VSWTCH}	m->tio.c_cc[VSWTCH]   = 0000;
291XIF{VSTART}	m->tio.c_cc[VSTART]   = Ctrl('Q');
292XIF{VSTOP}	m->tio.c_cc[VSTOP]    = Ctrl('S');
293XIF{VSUSP}	m->tio.c_cc[VSUSP]    = Ctrl('Z');
294XIF{VDSUSP}	m->tio.c_cc[VDSUSP]   = Ctrl('Y');
295XIF{VREPRINT}	m->tio.c_cc[VREPRINT] = Ctrl('R');
296XIF{VDISCARD}	m->tio.c_cc[VDISCARD] = Ctrl('O');
297XIF{VWERASE}	m->tio.c_cc[VWERASE]  = Ctrl('W');
298XIF{VLNEXT}	m->tio.c_cc[VLNEXT]   = Ctrl('V');
299XIF{VSTATUS}	m->tio.c_cc[VSTATUS]  = Ctrl('T');
300
301  if (ttyflag)
302    {
303      m->tio.c_cc[VMIN] = TTYVMIN;
304      m->tio.c_cc[VTIME] = TTYVTIME;
305    }
306
307# ifdef HPUX_LTCHARS_HACK
308  m->m_ltchars.t_suspc =  Ctrl('Z');
309  m->m_ltchars.t_dsuspc = Ctrl('Y');
310  m->m_ltchars.t_rprntc = Ctrl('R');
311  m->m_ltchars.t_flushc = Ctrl('O');
312  m->m_ltchars.t_werasc = Ctrl('W');
313  m->m_ltchars.t_lnextc = Ctrl('V');
314# endif /* HPUX_LTCHARS_HACK */
315
316#else /* POSIX */
317
318# ifdef TERMIO
319  debug1("InitTTY: nonPOSIX, struct termio a la Motorola SYSV68 (%d)\n", ttyflag);
320  /* struct termio tio 
321   * defaults, as seen on Mototola SYSV68:
322   * input: 7bit, CR->NL, ^S/^Q flow control 
323   * output: POSTprocessing: NL->NL-CR, Tabs to spaces
324   * control: 9600baud, 8bit CSIZE, enable input
325   * local: enable signals, erase/kill processing, echo on.
326   */
327IF{ISTRIP}	m->tio.c_iflag |= ISTRIP;
328IF{IXON}	m->tio.c_iflag |= IXON;
329
330  if (!ttyflag)	/* may not even be good for ptys.. */
331    {
332IF{OPOST}	m->tio.c_oflag |= OPOST;
333IF{ICRNL}	m->tio.c_iflag |= ICRNL;
334IF{ONLCR}	m->tio.c_oflag |= ONLCR;
335IF{TAB3}	m->tio.c_oflag |= TAB3;
336    }
337
338#ifdef __bsdi__
339		)-: cannot handle BSDI without POSIX
340#else
341IF{B9600}	m->tio.c_cflag  = B9600;
342#endif
343IF{CS8} 	m->tio.c_cflag |= CS8;
344IF{CREAD}	m->tio.c_cflag |= CREAD;
345
346  if (!ttyflag)
347    {
348IF{ISIG}	m->tio.c_lflag |= ISIG;
349IF{ICANON}	m->tio.c_lflag |= ICANON;
350IF{ECHO}	m->tio.c_lflag |= ECHO;
351    }
352IF{ECHOE}	m->tio.c_lflag |= ECHOE;
353IF{ECHOK}	m->tio.c_lflag |= ECHOK;
354
355XIF{VINTR}	m->tio.c_cc[VINTR]  = Ctrl('C');
356XIF{VQUIT}	m->tio.c_cc[VQUIT]  = Ctrl('\\');
357XIF{VERASE}	m->tio.c_cc[VERASE] = 0177; /* DEL */
358XIF{VKILL}	m->tio.c_cc[VKILL]  = Ctrl('H');
359XIF{VEOF}	m->tio.c_cc[VEOF]   = Ctrl('D');
360XIF{VEOL}	m->tio.c_cc[VEOL]   = 0377;
361XIF{VEOL2}	m->tio.c_cc[VEOL2]  = 0377;
362XIF{VSWTCH}	m->tio.c_cc[VSWTCH] = 0000;
363
364  if (ttyflag)
365   {
366      m->tio.c_cc[VMIN] = TTYVMIN;
367      m->tio.c_cc[VTIME] = TTYVTIME;
368    } 
369
370# else /* TERMIO */
371  debug1("InitTTY: BSD: defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
372  m->m_ttyb.sg_ispeed = B9600;
373  m->m_ttyb.sg_ospeed = B9600;
374  m->m_ttyb.sg_erase  = 0177; /*DEL */
375  m->m_ttyb.sg_kill   = Ctrl('H');
376  if (!ttyflag)
377    m->m_ttyb.sg_flags = CRMOD | ECHO
378IF{ANYP}	| ANYP
379    ;
380  else
381    m->m_ttyb.sg_flags = CBREAK
382IF{ANYP}	| ANYP
383    ;
384
385  m->m_tchars.t_intrc   = Ctrl('C');
386  m->m_tchars.t_quitc   = Ctrl('\\');
387  m->m_tchars.t_startc  = Ctrl('Q');
388  m->m_tchars.t_stopc   = Ctrl('S');
389  m->m_tchars.t_eofc    = Ctrl('D');
390  m->m_tchars.t_brkc    = -1;
391
392  m->m_ltchars.t_suspc  = Ctrl('Z');
393  m->m_ltchars.t_dsuspc = Ctrl('Y');
394  m->m_ltchars.t_rprntc = Ctrl('R');
395  m->m_ltchars.t_flushc = Ctrl('O');
396  m->m_ltchars.t_werasc = Ctrl('W');
397  m->m_ltchars.t_lnextc = Ctrl('V');
398
399IF{NTTYDISC}	m->m_ldisc = NTTYDISC;
400
401  m->m_lmode = 0
402IF{LDECCTQ}	| LDECCTQ
403IF{LCTLECH}	| LCTLECH
404IF{LPASS8}	| LPASS8
405IF{LCRTKIL}	| LCRTKIL
406IF{LCRTERA}	| LCRTERA
407IF{LCRTBS}	| LCRTBS
408  ;
409# endif /* TERMIO */
410#endif /* POSIX */
411
412#if defined(ENCODINGS) && defined(TIOCKSET)
413  m->m_jtchars.t_ascii = 'J';
414  m->m_jtchars.t_kanji = 'B';
415  m->m_knjmode = KM_ASCII | KM_SYSSJIS;
416#endif
417}
418
419void 
420SetTTY(fd, mp)
421int fd;
422struct mode *mp;
423{
424  errno = 0;
425#ifdef POSIX
426  tcsetattr(fd, TCSADRAIN, &mp->tio);
427# ifdef HPUX_LTCHARS_HACK
428  ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
429# endif
430#else
431# ifdef TERMIO
432  ioctl(fd, TCSETAW, (char *)&mp->tio);
433#  ifdef CYTERMIO
434  if (mp->tio.c_line == 3)
435    {
436      ioctl(fd, LDSETMAPKEY, (char *)&mp->m_mapkey);
437      ioctl(fd, LDSETMAPSCREEN, (char *)&mp->m_mapscreen);
438      ioctl(fd, LDSETBACKSPACE, (char *)&mp->m_backspace);
439    }
440#  endif
441# else
442  /* ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb); */
443  ioctl(fd, TIOCSETC, (char *)&mp->m_tchars);
444  ioctl(fd, TIOCLSET, (char *)&mp->m_lmode);
445  ioctl(fd, TIOCSETD, (char *)&mp->m_ldisc);
446  ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb);
447  ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars); /* moved here for apollo. jw */
448# endif
449#endif
450#if defined(ENCODINGS) && defined(TIOCKSET)
451  ioctl(fd, TIOCKSETC, &mp->m_jtchars);
452  ioctl(fd, TIOCKSET, &mp->m_knjmode);
453#endif
454  if (errno)
455    Msg(errno, "SetTTY (fd %d): ioctl failed", fd);
456}
457
458void
459GetTTY(fd, mp)
460int fd;
461struct mode *mp;
462{
463  errno = 0;
464#ifdef POSIX
465  tcgetattr(fd, &mp->tio);
466# ifdef HPUX_LTCHARS_HACK
467  ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
468# endif
469#else
470# ifdef TERMIO
471  ioctl(fd, TCGETA, (char *)&mp->tio);
472#  ifdef CYTERMIO
473  if (mp->tio.c_line == 3)
474    {
475      ioctl(fd, LDGETMAPKEY, (char *)&mp->m_mapkey);
476      ioctl(fd, LDGETMAPSCREEN, (char *)&mp->m_mapscreen);
477      ioctl(fd, LDGETBACKSPACE, (char *)&mp->m_backspace);
478    }
479  else
480    {
481      mp->m_mapkey = NOMAPKEY;
482      mp->m_mapscreen = NOMAPSCREEN;
483      mp->m_backspace = '\b';
484    }
485#  endif
486# else
487  ioctl(fd, TIOCGETP, (char *)&mp->m_ttyb);
488  ioctl(fd, TIOCGETC, (char *)&mp->m_tchars);
489  ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
490  ioctl(fd, TIOCLGET, (char *)&mp->m_lmode);
491  ioctl(fd, TIOCGETD, (char *)&mp->m_ldisc);
492# endif
493#endif
494#if defined(ENCODINGS) && defined(TIOCKSET)
495  ioctl(fd, TIOCKGETC, &mp->m_jtchars);
496  ioctl(fd, TIOCKGET, &mp->m_knjmode);
497#endif
498  if (errno)
499    Msg(errno, "GetTTY (fd %d): ioctl failed", fd);
500}
501
502/*
503 * needs interrupt = iflag and flow = d->d_flow
504 */
505void
506SetMode(op, np, flow, interrupt)
507struct mode *op, *np;
508int flow, interrupt;
509{
510  *np = *op;
511
512  ASSERT(display);
513#if defined(TERMIO) || defined(POSIX)
514# ifdef CYTERMIO
515  np->m_mapkey = NOMAPKEY;
516  np->m_mapscreen = NOMAPSCREEN;
517  np->tio.c_line = 0;
518# endif
519IF{ICRNL}  np->tio.c_iflag &= ~ICRNL;
520IF{ISTRIP}  np->tio.c_iflag &= ~ISTRIP;
521IF{ONLCR}  np->tio.c_oflag &= ~ONLCR;
522  np->tio.c_lflag &= ~(ICANON | ECHO);
523  /*
524   * From Andrew Myers (andru@tonic.lcs.mit.edu)
525   * to avoid ^V^V-Problem on OSF1
526   */
527IF{IEXTEN}  np->tio.c_lflag &= ~IEXTEN;
528
529  /*
530   * Unfortunately, the master process never will get SIGINT if the real
531   * terminal is different from the one on which it was originaly started
532   * (process group membership has not been restored or the new tty could not
533   * be made controlling again). In my solution, it is the attacher who
534   * receives SIGINT (because it is always correctly associated with the real
535   * tty) and forwards it to the master [kill(MasterPid, SIGINT)]. 
536   * Marc Boucher (marc@CAM.ORG)
537   */
538  if (interrupt)
539    np->tio.c_lflag |= ISIG;
540  else
541    np->tio.c_lflag &= ~ISIG;
542  /* 
543   * careful, careful catche monkey..
544   * never set VMIN and VTIME to zero, if you want blocking io.
545   *
546   * We may want to do a VMIN > 0, VTIME > 0 read on the ptys too, to 
547   * reduce interrupt frequency.  But then we would not know how to 
548   * handle read returning 0. jw.
549   */
550  np->tio.c_cc[VMIN] = 1;
551  np->tio.c_cc[VTIME] = 0;
552  if (!interrupt || !flow)
553    np->tio.c_cc[VINTR] = VDISABLE;
554  np->tio.c_cc[VQUIT] = VDISABLE;
555  if (flow == 0)
556    {
557XIF{VSTART}	np->tio.c_cc[VSTART] = VDISABLE;
558XIF{VSTOP}	np->tio.c_cc[VSTOP] = VDISABLE;
559      np->tio.c_iflag &= ~IXON;
560    }
561XIF{VDISCARD}	np->tio.c_cc[VDISCARD] = VDISABLE;
562XIF{VLNEXT}	np->tio.c_cc[VLNEXT] = VDISABLE;
563XIF{VSTATUS}	np->tio.c_cc[VSTATUS] = VDISABLE;
564XIF{VSUSP}	np->tio.c_cc[VSUSP] = VDISABLE;
565XIF{VERASE}	np->tio.c_cc[VERASE] = VDISABLE;
566XIF{VKILL}	np->tio.c_cc[VKILL] = VDISABLE;
567# ifdef HPUX_LTCHARS_HACK
568  np->m_ltchars.t_suspc  = VDISABLE;
569  np->m_ltchars.t_dsuspc = VDISABLE;
570  np->m_ltchars.t_rprntc = VDISABLE;
571  np->m_ltchars.t_flushc = VDISABLE;
572  np->m_ltchars.t_werasc = VDISABLE;
573  np->m_ltchars.t_lnextc = VDISABLE;
574# else /* HPUX_LTCHARS_HACK */
575XIF{VDSUSP}	np->tio.c_cc[VDSUSP] = VDISABLE;
576XIF{VREPRINT}	np->tio.c_cc[VREPRINT] = VDISABLE;
577XIF{VWERASE}	np->tio.c_cc[VWERASE] = VDISABLE;
578# endif /* HPUX_LTCHARS_HACK */
579#else /* TERMIO || POSIX */
580  if (!interrupt || !flow)
581    np->m_tchars.t_intrc = -1;
582  np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
583  np->m_ttyb.sg_flags |= CBREAK;
584# if defined(CYRILL) && defined(CSTYLE) && defined(CS_8BITS)
585  np->m_ttyb.sg_flags &= ~CSTYLE;
586  np->m_ttyb.sg_flags |= CS_8BITS;
587# endif
588  np->m_tchars.t_quitc = -1;
589  if (flow == 0)
590    {
591      np->m_tchars.t_startc = -1;
592      np->m_tchars.t_stopc = -1;
593    }
594  np->m_ltchars.t_suspc = -1;
595  np->m_ltchars.t_dsuspc = -1;
596  np->m_ltchars.t_flushc = -1;
597  np->m_ltchars.t_lnextc = -1;
598#endif /* defined(TERMIO) || defined(POSIX) */
599}
600
601/* operates on display */
602void
603SetFlow(on)
604int on;
605{
606  ASSERT(display);
607  if (D_flow == on)
608    return;
609#if defined(TERMIO) || defined(POSIX)
610  if (on)
611    {
612      D_NewMode.tio.c_cc[VINTR] = iflag ? D_OldMode.tio.c_cc[VINTR] : VDISABLE;
613XIF{VSTART}	D_NewMode.tio.c_cc[VSTART] = D_OldMode.tio.c_cc[VSTART];
614XIF{VSTOP}	D_NewMode.tio.c_cc[VSTOP] = D_OldMode.tio.c_cc[VSTOP];
615      D_NewMode.tio.c_iflag |= D_OldMode.tio.c_iflag & IXON;
616    }
617  else
618    {
619      D_NewMode.tio.c_cc[VINTR] = VDISABLE;
620XIF{VSTART}	D_NewMode.tio.c_cc[VSTART] = VDISABLE;
621XIF{VSTOP}	D_NewMode.tio.c_cc[VSTOP] = VDISABLE;
622      D_NewMode.tio.c_iflag &= ~IXON;
623    }
624# ifdef POSIX
625  if (tcsetattr(D_userfd, TCSANOW, &D_NewMode.tio))
626# else
627  if (ioctl(D_userfd, TCSETAW, (char *)&D_NewMode.tio) != 0)
628# endif
629    debug1("SetFlow: ioctl errno %d\n", errno);
630#else /* POSIX || TERMIO */
631  if (on)
632    {
633      D_NewMode.m_tchars.t_intrc = iflag ? D_OldMode.m_tchars.t_intrc : -1;
634      D_NewMode.m_tchars.t_startc = D_OldMode.m_tchars.t_startc;
635      D_NewMode.m_tchars.t_stopc = D_OldMode.m_tchars.t_stopc;
636    }
637  else
638    {
639      D_NewMode.m_tchars.t_intrc = -1;
640      D_NewMode.m_tchars.t_startc = -1;
641      D_NewMode.m_tchars.t_stopc = -1;
642    }
643  if (ioctl(D_userfd, TIOCSETC, (char *)&D_NewMode.m_tchars) != 0)
644    debug1("SetFlow: ioctl errno %d\n", errno);
645#endif /* POSIX || TERMIO */
646  D_flow = on;
647}
648
649/* parse commands from opt and modify m */
650int
651SttyMode(m, opt)
652struct mode *m;
653char *opt;
654{
655  static const char sep[] = " \t:;,";
656
657  if (!opt)
658    return 0;
659
660  while (*opt)
661    {
662      while (index(sep, *opt)) opt++;
663      if (*opt >= '0' && *opt <= '9')
664        {
665	  if (SetBaud(m, atoi(opt), atoi(opt)))
666	    return -1;
667	}
668      else if (!strncmp("cs7", opt, 3))
669        {
670#if defined(POSIX) || defined(TERMIO)
671	  m->tio.c_cflag &= ~CSIZE;
672	  m->tio.c_cflag |= CS7;
673#else
674	  m->m_lmode &= ~LPASS8;
675#endif
676	}
677      else if (!strncmp("cs8", opt, 3))
678	{
679#if defined(POSIX) || defined(TERMIO)
680	  m->tio.c_cflag &= ~CSIZE;
681	  m->tio.c_cflag |= CS8;
682#else
683	  m->m_lmode |= LPASS8;
684#endif
685	}
686      else if (!strncmp("istrip", opt, 6))
687	{
688#if defined(POSIX) || defined(TERMIO)
689	  m->tio.c_iflag |= ISTRIP;
690#else
691	  m->m_lmode &= ~LPASS8;
692#endif
693        }
694      else if (!strncmp("-istrip", opt, 7))
695	{
696#if defined(POSIX) || defined(TERMIO)
697	  m->tio.c_iflag &= ~ISTRIP;
698#else
699	  m->m_lmode |= LPASS8;
700#endif
701        }
702      else if (!strncmp("ixon", opt, 4))
703	{
704#if defined(POSIX) || defined(TERMIO)
705	  m->tio.c_iflag |= IXON;
706#else
707	  debug("SttyMode: no ixon in old bsd land.\n");
708#endif
709        }
710      else if (!strncmp("-ixon", opt, 5))
711	{
712#if defined(POSIX) || defined(TERMIO)
713	  m->tio.c_iflag &= ~IXON;
714#else
715	  debug("SttyMode: no -ixon in old bsd land.\n");
716#endif
717        }
718      else if (!strncmp("ixoff", opt, 5))
719	{
720#if defined(POSIX) || defined(TERMIO)
721	  m->tio.c_iflag |= IXOFF;
722#else
723	  m->m_ttyb.sg_flags |= TANDEM;
724#endif
725        }
726      else if (!strncmp("-ixoff", opt, 6))
727	{
728#if defined(POSIX) || defined(TERMIO)
729	  m->tio.c_iflag &= ~IXOFF;
730#else
731	  m->m_ttyb.sg_flags &= ~TANDEM;
732#endif
733        }
734      else if (!strncmp("crtscts", opt, 7))
735	{
736#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
737	  m->tio.c_cflag |= CRTSCTS;
738#endif
739	}
740      else if (!strncmp("-crtscts", opt, 8))
741        {
742#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
743	  m->tio.c_cflag &= ~CRTSCTS;
744#endif
745	}
746      else
747        return -1;
748      while (*opt && !index(sep, *opt)) opt++;
749    }
750  return 0;
751}
752
753/*
754 *  Job control handling
755 *
756 *  Somehow the ultrix session handling is broken, so use
757 *  the bsdish variant.
758 */
759
760/*ARGSUSED*/
761void
762brktty(fd)
763int fd;
764{
765#if defined(POSIX) && !defined(ultrix)
766  if (separate_sids)
767    setsid();		/* will break terminal affiliation */
768  /* GNU added for Hurd systems 2001-10-10 */
769# if defined(BSD) && defined(TIOCSCTTY) && !defined(__GNU__)
770  ioctl(fd, TIOCSCTTY, (char *)0);
771# endif /* BSD && TIOCSCTTY */
772#else /* POSIX */
773# ifdef SYSV
774  if (separate_sids)
775    setpgrp();		/* will break terminal affiliation */
776# else /* SYSV */
777#  ifdef BSDJOBS
778  int devtty;
779
780  if ((devtty = open("/dev/tty", O_RDWR | O_NONBLOCK)) >= 0)
781    {
782      if (ioctl(devtty, TIOCNOTTY, (char *)0))
783        debug2("brktty: ioctl(devtty=%d, TIOCNOTTY, 0) = %d\n", devtty, errno);
784      close(devtty);
785    }
786#  endif /* BSDJOBS */
787# endif /* SYSV */
788#endif /* POSIX */
789}
790
791int
792fgtty(fd)
793int fd;
794{
795#ifdef BSDJOBS
796  int mypid;
797
798  mypid = getpid();
799
800  /* The next lines should be obsolete. Can anybody check if they
801   * are really needed on the BSD platforms?
802   *
803   * this is to avoid the message:
804   *	fgtty: Not a typewriter (25)
805   */
806# if defined(__osf__) || (BSD >= 199103) || defined(ISC)
807  if (separate_sids)
808    setsid();	/* should be already done */
809#  ifdef TIOCSCTTY
810  ioctl(fd, TIOCSCTTY, (char *)0);
811#  endif
812# endif
813
814# ifdef POSIX
815  if (separate_sids)
816    if (tcsetpgrp(fd, mypid))
817      {
818        debug1("fgtty: tcsetpgrp: %d\n", errno);
819        return -1;
820      }
821# else /* POSIX */
822  if (ioctl(fd, TIOCSPGRP, (char *)&mypid) != 0)
823    debug1("fgtty: TIOSETPGRP: %d\n", errno);
824#  ifndef SYSV	/* Already done in brktty():setpgrp() */
825  if (separate_sids)
826    if (setpgrp(fd, mypid))
827      debug1("fgtty: setpgrp: %d\n", errno);
828#  endif
829# endif /* POSIX */
830#endif /* BSDJOBS */
831  return 0;
832}
833
834/* 
835 * The alm boards on our sparc center 1000 have a lousy driver.
836 * We cannot generate long breaks unless we use the most ugly form
837 * of ioctls. jw.
838 */
839#ifdef POSIX
840int breaktype = 2;
841#else /* POSIX */
842# ifdef TCSBRK
843int breaktype = 1;
844# else
845int breaktype = 0;
846# endif
847#endif /* POSIX */
848
849#if defined(sun) && !defined(SVR4)
850# define HAVE_SUPER_TCSENDBREAK
851#endif
852
853/*
854 * type:
855 *  0:	TIOCSBRK / TIOCCBRK
856 *  1:	TCSBRK
857 *  2:	tcsendbreak()
858 * n: approximate duration in 1/4 seconds.
859 */
860static void
861DoSendBreak(fd, n, type)
862int fd, n, type;
863{
864  switch (type)
865    {
866    case 2:	/* tcsendbreak() =============================== */
867#ifdef POSIX
868# ifdef HAVE_SUPER_TCSENDBREAK
869      /* There is one rare case that I have tested, where tcsendbreak works
870       * really great: this was an alm driver that came with SunOS 4.1.3
871       * If you have this one, define the above symbol.
872       * here we can use the second parameter to specify the duration.
873       */
874      debug2("tcsendbreak(fd=%d, %d)\n", fd, n);
875      if (tcsendbreak(fd, n) < 0)
876        Msg(errno, "cannot send BREAK (tcsendbreak)");
877# else
878      /* 
879       * here we hope, that multiple calls to tcsendbreak() can
880       * be concatenated to form a long break, as we do not know 
881       * what exact interpretation the second parameter has:
882       *
883       * - sunos 4: duration in quarter seconds
884       * - sunos 5: 0 a short break, nonzero a tcdrain()
885       * - hpux, irix: ignored
886       * - mot88: duration in milliseconds
887       * - aix: duration in milliseconds, but 0 is 25 milliseconds.
888       */
889      debug2("%d * tcsendbreak(fd=%d, 0)\n", n, fd);
890	{
891	  int i;
892
893	  if (!n)
894	    n++;
895	  for (i = 0; i < n; i++)
896	    if (tcsendbreak(fd, 0) < 0)
897	      {
898		Msg(errno, "cannot send BREAK (tcsendbreak SVR4)");
899		return;
900	      }
901	}
902# endif
903#else /* POSIX */
904      Msg(0, "tcsendbreak() not available, change breaktype");
905#endif /* POSIX */
906      break;
907
908    case 1:	/* TCSBRK ======================================= */
909#ifdef TCSBRK
910      if (!n)
911        n++;
912      /*
913       * Here too, we assume that short breaks can be concatenated to 
914       * perform long breaks. But for SOLARIS, this is not true, of course.
915       */
916      debug2("%d * TCSBRK fd=%d\n", n, fd);
917	{
918	  int i;
919
920	  for (i = 0; i < n; i++)
921	    if (ioctl(fd, TCSBRK, (char *)0) < 0)
922	      {
923		Msg(errno, "Cannot send BREAK (TCSBRK)");
924		return;
925	      }
926	}
927#else /* TCSBRK */
928      Msg(0, "TCSBRK not available, change breaktype");
929#endif /* TCSBRK */
930      break;
931
932    case 0:	/* TIOCSBRK / TIOCCBRK ========================== */
933#if defined(TIOCSBRK) && defined(TIOCCBRK)
934      /*
935       * This is very rude. Screen actively celebrates the break.
936       * But it may be the only save way to issue long breaks.
937       */
938      debug("TIOCSBRK TIOCCBRK\n");
939      if (ioctl(fd, TIOCSBRK, (char *)0) < 0)
940        {
941	  Msg(errno, "Can't send BREAK (TIOCSBRK)");
942	  return;
943	}
944      sleep1000(n ? n * 250 : 250);
945      if (ioctl(fd, TIOCCBRK, (char *)0) < 0)
946        {
947	  Msg(errno, "BREAK stuck!!! -- HELP! (TIOCCBRK)");
948	  return;
949	}
950#else /* TIOCSBRK && TIOCCBRK */
951      Msg(0, "TIOCSBRK/CBRK not available, change breaktype");
952#endif /* TIOCSBRK && TIOCCBRK */
953      break;
954
955    default:	/* unknown ========================== */
956      Msg(0, "Internal SendBreak error: method %d unknown", type);
957    }
958}
959
960/* 
961 * Send a break for n * 0.25 seconds. Tty must be PLAIN.
962 * The longest possible break allowed here is 15 seconds.
963 */
964
965void 
966SendBreak(wp, n, closeopen)
967struct win *wp;
968int n, closeopen;
969{
970  sigret_t (*sigalrm)__P(SIGPROTOARG);
971
972#ifdef BUILTIN_TELNET
973  if (wp->w_type == W_TYPE_TELNET)
974    {
975      TelBreak(wp);
976      return;
977    }
978#endif
979  if (wp->w_type != W_TYPE_PLAIN)
980    return;
981
982  debug3("break(%d, %d) fd %d\n", n, closeopen, wp->w_ptyfd);
983
984#ifdef POSIX
985  (void) tcflush(wp->w_ptyfd, TCIOFLUSH);
986#else
987# ifdef TIOCFLUSH
988  (void) ioctl(wp->w_ptyfd, TIOCFLUSH, (char *)0);
989# endif /* TIOCFLUSH */
990#endif /* POSIX */
991
992  if (closeopen)
993    {
994      close(wp->w_ptyfd);
995      sleep1000(n ? n * 250 : 250);
996      if ((wp->w_ptyfd = OpenTTY(wp->w_tty, wp->w_cmdargs[1])) < 1)
997	{
998	  Msg(0, "Ouch, cannot reopen line %s, please try harder", wp->w_tty);
999	  return;
1000	}
1001      (void) fcntl(wp->w_ptyfd, F_SETFL, FNBLOCK);
1002    }
1003  else
1004    {
1005      sigalrm = signal(SIGALRM, SigAlrmDummy);
1006      alarm(15);
1007
1008      DoSendBreak(wp->w_ptyfd, n, breaktype);
1009
1010      alarm(0);
1011      signal(SIGALRM, sigalrm);
1012    }
1013  debug("            broken.\n");
1014}
1015
1016/*
1017 *  Console grabbing
1018 */
1019
1020#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
1021
1022static struct event consredir_ev;
1023static int consredirfd[2] = {-1, -1};
1024
1025static void
1026consredir_readev_fn(ev, data)
1027struct event *ev;
1028char *data;
1029{
1030  char *p, *n, buf[256];
1031  int l;
1032
1033  if (!console_window || (l = read(consredirfd[0], buf, sizeof(buf))) <= 0)
1034    {
1035      close(consredirfd[0]);
1036      close(consredirfd[1]);
1037      consredirfd[0] = consredirfd[1] = -1;
1038      evdeq(ev);
1039      return;
1040    }
1041  for (p = n = buf; l > 0; n++, l--)
1042    if (*n == '\n')
1043      {
1044        if (n > p)
1045	  WriteString(console_window, p, n - p);
1046        WriteString(console_window, "\r\n", 2);
1047        p = n + 1;
1048      }
1049  if (n > p)
1050    WriteString(console_window, p, n - p);
1051}
1052
1053#endif
1054
1055/*ARGSUSED*/
1056int
1057TtyGrabConsole(fd, on, rc_name)
1058int fd, on;
1059char *rc_name;
1060{
1061#if defined(TIOCCONS) && !defined(linux)
1062  struct display *d;
1063  int ret = 0;
1064  int sfd = -1;
1065
1066  if (on < 0)
1067    return 0;		/* pty close will ungrab */
1068  if (on)
1069    {
1070      if (displays == 0)
1071	{
1072	  Msg(0, "I need a display");
1073	  return -1;
1074	}
1075      for (d = displays; d; d = d->d_next)
1076	if (strcmp(d->d_usertty, "/dev/console") == 0)
1077	  break;
1078      if (d)
1079	{
1080	  Msg(0, "too dangerous - screen is running on /dev/console");
1081	  return -1;
1082	}
1083    }
1084
1085  if (!on)
1086    {
1087      char *slave;
1088      if ((fd = OpenPTY(&slave)) < 0)
1089	{
1090	  Msg(errno, "%s: could not open detach pty master", rc_name);
1091	  return -1;
1092	}
1093      if ((sfd = open(slave, O_RDWR | O_NOCTTY)) < 0)
1094	{
1095	  Msg(errno, "%s: could not open detach pty slave", rc_name);
1096	  close(fd);
1097	  return -1;
1098	}
1099    }
1100  if (UserContext() == 1)
1101    UserReturn(ioctl(fd, TIOCCONS, (char *)&on));
1102  ret = UserStatus();
1103  if (ret)
1104    Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
1105  if (!on)
1106    {
1107      close(sfd);
1108      close(fd);
1109    }
1110  return ret;
1111
1112#else
1113# if defined(SRIOCSREDIR) || defined(linux)
1114  struct display *d;
1115#  ifdef SRIOCSREDIR
1116  int cfd;
1117#  else
1118  struct mode new1, new2;
1119  char *slave;
1120#  endif
1121
1122  if (on > 0)
1123    {
1124      if (displays == 0)
1125	{
1126	  Msg(0, "I need a display");
1127	  return -1;
1128	}
1129      for (d = displays; d; d = d->d_next)
1130	if (strcmp(d->d_usertty, "/dev/console") == 0)
1131	  break;
1132      if (d)
1133	{
1134	  Msg(0, "too dangerous - screen is running on /dev/console");
1135	  return -1;
1136	}
1137    }
1138  if (consredirfd[0] >= 0)
1139    {
1140      evdeq(&consredir_ev);
1141      close(consredirfd[0]);
1142      close(consredirfd[1]);
1143      consredirfd[0] = consredirfd[1] = -1;
1144    }
1145  if (on <= 0)
1146    return 0;
1147#  ifdef SRIOCSREDIR
1148  if ((cfd = secopen("/dev/console", O_RDWR|O_NOCTTY, 0)) == -1)
1149    {
1150      Msg(errno, "/dev/console");
1151      return -1;
1152    }
1153  if (pipe(consredirfd))
1154    {
1155      Msg(errno, "pipe");
1156      close(cfd);
1157      consredirfd[0] = consredirfd[1] = -1;
1158      return -1;
1159    }
1160  if (ioctl(cfd, SRIOCSREDIR, consredirfd[1]))
1161    {
1162      Msg(errno, "SRIOCSREDIR ioctl");
1163      close(cfd);
1164      close(consredirfd[0]);
1165      close(consredirfd[1]);
1166      consredirfd[0] = consredirfd[1] = -1;
1167      return -1;
1168    }
1169  close(cfd);
1170#  else
1171  /* special linux workaround for a too restrictive kernel */
1172  if ((consredirfd[0] = OpenPTY(&slave)) < 0)
1173    {
1174      Msg(errno, "%s: could not open detach pty master", rc_name);
1175      return -1;
1176    }
1177  if ((consredirfd[1] = open(slave, O_RDWR | O_NOCTTY)) < 0)
1178    {
1179      Msg(errno, "%s: could not open detach pty slave", rc_name);
1180      close(consredirfd[0]);
1181      return -1;
1182    }
1183  InitTTY(&new1, 0);
1184  SetMode(&new1, &new2, 0, 0);
1185  SetTTY(consredirfd[1], &new2);
1186  if (UserContext() == 1)
1187    UserReturn(ioctl(consredirfd[1], TIOCCONS, (char *)&on));
1188  if (UserStatus())
1189    {
1190      Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
1191      close(consredirfd[0]);
1192      close(consredirfd[1]);
1193      return -1;
1194    }
1195#  endif
1196  consredir_ev.fd = consredirfd[0];
1197  consredir_ev.type = EV_READ;
1198  consredir_ev.handler = consredir_readev_fn;
1199  evenq(&consredir_ev);
1200  return 0;
1201# else
1202  if (on > 0)
1203    Msg(0, "%s: don't know how to grab the console", rc_name);
1204  return -1;
1205# endif
1206#endif
1207}
1208
1209/*
1210 * Read modem control lines of a physical tty and write them to buf
1211 * in a readable format.
1212 * Will not write more than 256 characters to buf.
1213 * Returns buf;
1214 */
1215char *
1216TtyGetModemStatus(fd, buf)
1217int fd;
1218char *buf;
1219{
1220  char *p = buf;
1221#ifdef TIOCGSOFTCAR
1222  unsigned int softcar;
1223#endif
1224#if defined(TIOCMGET) || defined(TIOCMODG)
1225  unsigned int mflags;
1226#else
1227# ifdef MCGETA
1228  /* this is yet another interface, found on hpux. grrr */
1229  mflag mflags;
1230IF{MDTR}#  define TIOCM_DTR MDTR
1231IF{MRTS}#  define TIOCM_RTS MRTS
1232IF{MDSR}#  define TIOCM_DSR MDSR
1233IF{MDCD}#  define TIOCM_CAR MDCD
1234IF{MRI}#  define TIOCM_RNG MRI
1235IF{MCTS}#  define TIOCM_CTS MCTS
1236# endif
1237#endif
1238#if defined(CLOCAL) || defined(CRTSCTS)
1239  struct mode mtio;	/* screen.h */
1240#endif
1241#if defined(CRTSCTS) || defined(TIOCM_CTS)
1242  int rtscts;
1243#endif
1244  int clocal;
1245
1246#if defined(CLOCAL) || defined(CRTSCTS)
1247  GetTTY(fd, &mtio);
1248#endif
1249  clocal = 0;
1250#ifdef CLOCAL
1251  if (mtio.tio.c_cflag & CLOCAL)
1252    {
1253      clocal = 1;
1254      *p++ = '{';
1255    }
1256#endif
1257
1258#ifdef TIOCM_CTS
1259# ifdef CRTSCTS
1260  if (!(mtio.tio.c_cflag & CRTSCTS))
1261    rtscts = 0;
1262  else
1263# endif /* CRTSCTS */
1264    rtscts = 1;
1265#endif /* TIOCM_CTS */
1266
1267#ifdef TIOCGSOFTCAR
1268  if (ioctl(fd, TIOCGSOFTCAR, (char *)&softcar) < 0)
1269    softcar = 0;
1270#endif
1271
1272#if defined(TIOCMGET) || defined(TIOCMODG) || defined(MCGETA)
1273# ifdef TIOCMGET
1274  if (ioctl(fd, TIOCMGET, (char *)&mflags) < 0)
1275# else
1276#  ifdef TIOCMODG
1277  if (ioctl(fd, TIOCMODG, (char *)&mflags) < 0)
1278#  else
1279  if (ioctl(fd, MCGETA, &mflags) < 0)
1280#  endif
1281# endif
1282    {
1283#ifdef TIOCGSOFTCAR
1284      sprintf(p, "NO-TTY? %s", softcar ? "(CD)" : "CD");
1285#else
1286      sprintf(p, "NO-TTY?");
1287#endif
1288      p += strlen(p);
1289    }
1290  else
1291    {
1292      char *s;
1293# ifdef FANCY_MODEM
1294#  ifdef TIOCM_LE
1295      if (!(mflags & TIOCM_LE))
1296        for (s = "!LE "; *s; *p++ = *s++);
1297#  endif
1298# endif /* FANCY_MODEM */
1299
1300# ifdef TIOCM_RTS
1301      s = "!RTS "; if (mflags & TIOCM_RTS) s++;
1302      while (*s) *p++ = *s++;
1303# endif
1304# ifdef TIOCM_CTS
1305      s = "!CTS "; 
1306      if (!rtscts)
1307        {
1308          *p++ = '(';
1309          s = "!CTS) "; 
1310	}
1311      if (mflags & TIOCM_CTS) s++;
1312      while (*s) *p++ = *s++;
1313# endif
1314
1315# ifdef TIOCM_DTR
1316      s = "!DTR "; if (mflags & TIOCM_DTR) s++;
1317      while (*s) *p++ = *s++;
1318# endif
1319# ifdef TIOCM_DSR
1320      s = "!DSR "; if (mflags & TIOCM_DSR) s++;
1321      while (*s) *p++ = *s++;
1322# endif
1323# if defined(TIOCM_CD) || defined(TIOCM_CAR)
1324      s = "!CD "; 
1325#  ifdef TIOCGSOFTCAR
1326      if (softcar)
1327	 {
1328	  *p++ = '(';
1329	  s = "!CD) ";
1330	 }
1331#  endif
1332#  ifdef TIOCM_CD
1333      if (mflags & TIOCM_CD) s++;
1334#  else
1335      if (mflags & TIOCM_CAR) s++;
1336#  endif
1337      while (*s) *p++ = *s++;
1338# endif
1339# if defined(TIOCM_RI) || defined(TIOCM_RNG)
1340#  ifdef TIOCM_RI
1341      if (mflags & TIOCM_RI)
1342#  else
1343      if (mflags & TIOCM_RNG)
1344#  endif
1345	for (s = "RI "; *s; *p++ = *s++);
1346# endif
1347# ifdef FANCY_MODEM
1348#  ifdef TIOCM_ST
1349      s = "!ST "; if (mflags & TIOCM_ST) s++;
1350      while (*s) *p++ = *s++;
1351#  endif
1352#  ifdef TIOCM_SR
1353      s = "!SR "; if (mflags & TIOCM_SR) s++;
1354      while (*s) *p++ = *s++;
1355#  endif
1356# endif /* FANCY_MODEM */
1357      if (p > buf && p[-1] == ' ')
1358        p--;
1359      *p = '\0';
1360    }
1361#else
1362# ifdef TIOCGSOFTCAR
1363  sprintf(p, " %s", softcar ? "(CD)", "CD");
1364  p += strlen(p);
1365# endif
1366#endif
1367  if (clocal)
1368    *p++ = '}';
1369  *p = '\0';
1370  return buf;
1371}
1372
1373/*
1374 * Old bsd-ish machines may not have any of the baudrate B... symbols.
1375 * We hope to detect them here, so that the btable[] below always has
1376 * many entries.
1377 */
1378#ifndef POSIX
1379# ifndef TERMIO
1380#  if !defined(B9600) && !defined(B2400) && !defined(B1200) && !defined(B300)
1381IFN{B0}#define		B0	0
1382IFN{B50}#define  	B50	1
1383IFN{B75}#define  	B75	2
1384IFN{B110}#define 	B110	3
1385IFN{B134}#define 	B134	4
1386IFN{B150}#define 	B150	5
1387IFN{B200}#define 	B200	6
1388IFN{B300}#define 	B300	7
1389IFN{B600}#define 	B600	8
1390IFN{B1200}#define	B1200	9
1391IFN{B1800}#define	B1800	10
1392IFN{B2400}#define	B2400	11
1393IFN{B4800}#define	B4800	12
1394IFN{B9600}#define	B9600	13
1395IFN{EXTA}#define	EXTA	14
1396IFN{EXTB}#define	EXTB	15
1397#  endif
1398# endif
1399#endif
1400
1401/*
1402 * On hpux, idx and sym will be different. 
1403 * Rumor has it that, we need idx in D_dospeed to make tputs
1404 * padding correct. 
1405 * Frequently used entries come first.
1406 */
1407static struct baud_values btable[] =
1408{
1409IF{B9600}	{	13,	9600,	B9600	},
1410IF{B19200}	{	14,	19200,	B19200	},
1411IF{EXTA}	{	14,	19200,	EXTA	},
1412IF{B38400}	{	15,	38400,	B38400	},
1413IF{EXTB}	{	15,	38400,	EXTB	},
1414IF{B57600}	{	16,	57600,	B57600	},
1415IF{B115200}	{	17,	115200,	B115200	},
1416IF{B230400}	{	18,	230400,	B230400	},
1417IF{B460800}	{	19,	460800,	B460800	},
1418IF{B7200}	{	13,	7200,	B7200	},
1419IF{B4800}	{	12,	4800,	B4800	},
1420IF{B3600}	{	12,	3600,	B3600	},
1421IF{B2400}	{	11,	2400,	B2400	},
1422IF{B1800}	{	10,	1800,	B1800	},
1423IF{B1200}	{	9,	1200,	B1200	},
1424IF{B900} 	{	9,	900,	B900	},
1425IF{B600} 	{	8,	600,	B600	},
1426IF{B300} 	{	7,	300, 	B300	},
1427IF{B200} 	{	6,	200, 	B200	},
1428IF{B150} 	{	5,	150,	B150	},
1429IF{B134} 	{	4,	134,	B134	},
1430IF{B110} 	{	3,	110,	B110	},
1431IF{B75}  	{	2,	75,	B75	},
1432IF{B50}  	{	1,	50,	B50	},
1433IF{B0}   	{	0,	0,	B0	},
1434		{	-1,	-1,	-1	}
1435};
1436
1437/*
1438 * baud may either be a bits-per-second value or a symbolic
1439 * value as returned by cfget?speed() 
1440 */
1441struct baud_values *
1442lookup_baud(baud)
1443int baud;
1444{
1445  struct baud_values *p;
1446
1447  for (p = btable; p->idx >= 0; p++)
1448    if (baud == p->bps || baud == p->sym)
1449      return p;
1450  return NULL;
1451}
1452
1453/*
1454 * change the baud rate in a mode structure.
1455 * ibaud and obaud are given in bit/second, or at your option as
1456 * termio B... symbols as defined in e.g. suns sys/ttydev.h
1457 * -1 means don't change.
1458 */
1459int
1460SetBaud(m, ibaud, obaud)
1461struct mode *m;
1462int ibaud, obaud;
1463{
1464  struct baud_values *ip, *op;
1465
1466  if ((!(ip = lookup_baud(ibaud)) && ibaud != -1) ||
1467      (!(op = lookup_baud(obaud)) && obaud != -1))
1468    return -1;
1469
1470#ifdef POSIX
1471  if (ip) cfsetispeed(&m->tio, ip->sym);
1472  if (op) cfsetospeed(&m->tio, op->sym);
1473#else /* POSIX */
1474# ifdef TERMIO
1475  if (ip)
1476    {
1477#  ifdef IBSHIFT
1478      m->tio.c_cflag &= ~(CBAUD << IBSHIFT);
1479      m->tio.c_cflag |= (ip->sym & CBAUD) << IBSHIFT;
1480#  else /* IBSHIFT */
1481      if (ibaud != obaud)
1482        return -1;
1483#  endif /* IBSHIFT */
1484    }
1485  if (op)
1486    {
1487      m->tio.c_cflag &= ~CBAUD;
1488      m->tio.c_cflag |= op->sym & CBAUD;
1489    }
1490# else /* TERMIO */
1491  if (ip) m->m_ttyb.sg_ispeed = ip->idx;
1492  if (op) m->m_ttyb.sg_ospeed = op->idx;
1493# endif /* TERMIO */
1494#endif /* POSIX */
1495  return 0;
1496}
1497
1498/*
1499 *  Write out the mode struct in a readable form
1500 */
1501
1502#ifdef DEBUG
1503void
1504DebugTTY(m)
1505struct mode *m;
1506{
1507  int i;
1508
1509#ifdef POSIX
1510  debug("struct termios tio:\n");
1511  debug1("c_iflag = %#x\n", (unsigned int)m->tio.c_iflag);
1512  debug1("c_oflag = %#x\n", (unsigned int)m->tio.c_oflag);
1513  debug1("c_cflag = %#x\n", (unsigned int)m->tio.c_cflag);
1514  debug1("c_lflag = %#x\n", (unsigned int)m->tio.c_lflag);
1515  debug1("cfgetospeed() = %d\n", (int)cfgetospeed(&m->tio));
1516  debug1("cfgetispeed() = %d\n", (int)cfgetispeed(&m->tio));
1517  for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
1518    {
1519      debug2("c_cc[%d] = %#x\n", i, m->tio.c_cc[i]);
1520    }
1521# ifdef HPUX_LTCHARS_HACK
1522  debug1("suspc     = %#02x\n", m->m_ltchars.t_suspc);
1523  debug1("dsuspc    = %#02x\n", m->m_ltchars.t_dsuspc);
1524  debug1("rprntc    = %#02x\n", m->m_ltchars.t_rprntc);
1525  debug1("flushc    = %#02x\n", m->m_ltchars.t_flushc);
1526  debug1("werasc    = %#02x\n", m->m_ltchars.t_werasc);
1527  debug1("lnextc    = %#02x\n", m->m_ltchars.t_lnextc);
1528# endif /* HPUX_LTCHARS_HACK */
1529#else /* POSIX */
1530# ifdef TERMIO
1531  debug("struct termio tio:\n");
1532  debug1("c_iflag = %04o\n", m->tio.c_iflag);
1533  debug1("c_oflag = %04o\n", m->tio.c_oflag);
1534  debug1("c_cflag = %04o\n", m->tio.c_cflag);
1535  debug1("c_lflag = %04o\n", m->tio.c_lflag);
1536  for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
1537    {
1538      debug2("c_cc[%d] = %04o\n", i, m->tio.c_cc[i]);
1539    }
1540# else /* TERMIO */
1541  debug1("sg_ispeed = %d\n",    m->m_ttyb.sg_ispeed);
1542  debug1("sg_ospeed = %d\n",    m->m_ttyb.sg_ospeed);
1543  debug1("sg_erase  = %#02x\n", m->m_ttyb.sg_erase);
1544  debug1("sg_kill   = %#02x\n", m->m_ttyb.sg_kill);
1545  debug1("sg_flags  = %#04x\n", (unsigned short)m->m_ttyb.sg_flags);
1546  debug1("intrc     = %#02x\n", m->m_tchars.t_intrc);
1547  debug1("quitc     = %#02x\n", m->m_tchars.t_quitc);
1548  debug1("startc    = %#02x\n", m->m_tchars.t_startc);
1549  debug1("stopc     = %#02x\n", m->m_tchars.t_stopc);
1550  debug1("eofc      = %#02x\n", m->m_tchars.t_eofc);
1551  debug1("brkc      = %#02x\n", m->m_tchars.t_brkc);
1552  debug1("suspc     = %#02x\n", m->m_ltchars.t_suspc);
1553  debug1("dsuspc    = %#02x\n", m->m_ltchars.t_dsuspc);
1554  debug1("rprntc    = %#02x\n", m->m_ltchars.t_rprntc);
1555  debug1("flushc    = %#02x\n", m->m_ltchars.t_flushc);
1556  debug1("werasc    = %#02x\n", m->m_ltchars.t_werasc);
1557  debug1("lnextc    = %#02x\n", m->m_ltchars.t_lnextc);
1558  debug1("ldisc     = %d\n",    m->m_ldisc);
1559  debug1("lmode     = %#x\n",   m->m_lmode);
1560# endif /* TERMIO */
1561#endif /* POSIX */
1562}
1563#endif /* DEBUG */
1564