1
/******************************************************************************
2
(c) 2002-2003 P.J. Caulfield patrick@debian.org
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
13
******************************************************************************
24
#include <sys/socket.h>
25
#include <sys/ioctl.h>
26
#include <sys/types.h>
28
#include <sys/fcntl.h>
29
#include <netdnet/dn.h>
30
#include <netdnet/dnetdb.h>
31
#include "dn_endian.h"
35
/* The global state */
40
/* Input state buffers & variables */
41
static unsigned char terminators[32];
42
static char rahead_buf[128];
43
static int rahead_len=0;
44
static char input_buf[1024];
45
static int input_len=0;
46
static int input_pos=0;
47
static char prompt_buf[1024];
48
static char prompt_len=0;
49
static char esc_buf[132];
51
static int max_read_len = sizeof(input_buf);
53
static int reading = 0;
54
static int insert_mode = 0;
55
static int echo_terminator = 0;
58
extern int char_timeout;
60
/* Output processors */
61
int (*send_input)(unsigned char *buf, int len, int flags);
62
int (*send_oob)(char oobchar, int discard);
64
static void send_input_buffer(int flags)
68
memcpy(buf, input_buf, input_len);
70
send_input(buf, input_len, flags);
71
input_len = input_pos = 0;
76
/* Raw write to terminal */
77
int tty_write(unsigned char *buf, int len)
84
write(termfd, "\r\n", 2);
86
write(termfd, &buf[i], 1);
96
void tty_echo_terminator(int a)
99
fprintf(stderr, "TTY: echo terminators = %d\n", a);
104
void tty_set_default_terminators()
107
fprintf(stderr, "TTY: set default terminators\n");
109
/* All control chars except ^R ^U ^W, BS & HT */
110
/* ie 18, 21, 23, 8, 9 */
111
memset(terminators, 0, sizeof(terminators));
112
terminators[0] = 0x7F;
113
terminators[1] = 0xFE;
114
terminators[2] = 0xAD;
115
terminators[3] = 0xFF;
118
void tty_set_terminators(unsigned char *buf, int len)
121
fprintf(stderr, "TTY: set terminators... %d bytes\n", len);
122
memset(terminators, 0, sizeof(terminators));
123
memcpy(terminators, buf, len);
126
void tty_start_read(char *prompt, int len, int promptlen)
129
fprintf(stderr, "TTY: start_read promptlen = %d, maxlen=%d\n",
131
if (promptlen) write(termfd, prompt, promptlen);
132
if (len < 0) len = sizeof(input_buf);
134
/* Save the actual prompt in one buffer and the prefilled
135
data in the input buffer */
136
memcpy(prompt_buf, prompt, promptlen);
137
prompt_len = promptlen;
139
memcpy(input_buf, prompt+promptlen, len);
141
input_pos = input_len;
144
/* Now add in any typeahead */
147
int copylen = rahead_len;
150
fprintf(stderr, "TTY: readahead = %d bytes\n", rahead_len);
152
/* Don't overflow the input buffer */
153
if (input_len + copylen > sizeof(input_buf))
154
copylen = sizeof(input_buf)-input_len;
156
memcpy(input_buf+input_len, rahead_buf, copylen);
157
input_len += copylen;
163
void tty_set_timeout(unsigned short to)
168
void tty_clear_typeahead()
173
void tty_set_maxlen(unsigned short len)
178
/* Set/Reset the local TTY mode */
179
int tty_setup(char *name, int setup)
181
struct termios new_term;
182
static struct termios old_term;
186
termfd = open(name, O_RDWR);
188
tcgetattr(termfd, &old_term);
191
new_term.c_iflag &= ~BRKINT;
192
new_term.c_iflag |= IGNBRK;
193
new_term.c_lflag &= ~ISIG;
194
new_term.c_cc[VMIN] = 1;
195
new_term.c_cc[VTIME] = 0;
196
new_term.c_lflag &= ~ICANON;
197
new_term.c_lflag &= ~(ECHO | ECHOCTL | ECHONL);
198
tcsetattr(termfd, TCSANOW, &new_term);
202
tcsetattr(termfd, TCSANOW, &old_term);
209
static short is_terminator(char c)
211
short termind, msk, aux;
214
aux = c - (termind * 8);
217
if (terminators[termind] && msk)
224
/* Erase to end of line */
225
static void erase_eol(void)
227
write(termfd, "\033[0K", 4);
230
/* Move to column "hpos", where hpos starts at 0 */
231
static void move_cursor_abs(int hpos)
235
sprintf(buf, "\r\033[%dC", hpos);
236
write(termfd, buf, strlen(buf));
240
void tty_send_unread()
242
send_input_buffer(0);
245
/* Input from keyboard */
246
int tty_process_terminal(unsigned char *buf, int len)
250
for (i=0; i<len; i++)
252
if (buf[i] == exit_char)
259
//PJC: is this right??
264
if (buf[i] == ESC && esc_len == 0)
266
esc_buf[esc_len++] = buf[i];
271
if (!esc_len && is_terminator(buf[i]))
275
write(termfd, &buf[i], 1);
277
input_buf[input_len++] = buf[i];
278
send_input_buffer(1);
283
/* Check for OOB - these discard input */
284
if (buf[i] == CTRL_C || buf[i] == CTRL_Y)
290
/* Check for OOB - these don't */
291
if (buf[i] == CTRL_Z || buf[i] == CTRL_T)
297
/* Still processing escape sequence */
300
esc_buf[esc_len++] = buf[i];
305
/* Process escape sequences */
306
if (strncmp(esc_buf, "\033[C", 3) == 0) /* Cursor RIGHT */
308
if (input_pos < input_len)
311
if (echo) write(termfd, esc_buf, esc_len);
315
if (strncmp(esc_buf, "\033[D", 3) == 0) /* Cursor LEFT */
320
if (echo) write(termfd, esc_buf, esc_len);
324
/* If we didn't process it above, then just send it to
328
send_input(esc_buf, esc_len, 2);
335
/* Process non-terminator control chars */
336
if (buf[i] < ' ' || buf[i] == DEL)
340
case CTRL_B: // Up a line
342
case CTRL_X: // delete input line
343
case CTRL_U: // delete input line
344
move_cursor_abs(prompt_len);
345
if (echo) erase_eol();
346
input_pos = input_len = 0;
348
case CTRL_H: // back to start of line
349
if (echo) move_cursor_abs(prompt_len);
352
case CTRL_A: /* switch overstrike/insert mode */
353
insert_mode = 1-insert_mode;
356
input_buf[input_len++] = buf[i];
357
send_input_buffer(1);
358
input_len = input_pos = 0;
365
input_len = input_pos;
366
if (echo) write(termfd, "\033[D \033[D", 7);
373
/* Read not active, store in the read ahead buffer */
376
if (rahead_len < sizeof(rahead_buf))
377
rahead_buf[rahead_len++] = buf[i];
383
write(termfd, &buf[i], 1);
385
/* Check for buffer overflow */
386
input_buf[input_pos++] = buf[i];
387
if (input_len < input_pos)
388
input_len = input_pos;
390
if (input_len >= max_read_len)
392
send_input_buffer(4);