Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/hetio.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 8685 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 /*
2 * Termios command line History and Editting for NetBSD sh (ash)
3 * Copyright (c) 1999
4 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
5 * Etc: Dave Cinege <dcinege@psychosis.com>
6 *
7 * You may use this code as you wish, so long as the original author(s)
8 * are attributed in any redistributions of the source code.
9 * This code is 'as is' with no warranty.
10 * This code may safely be consumed by a BSD or GPL license.
11 *
12 * v 0.5 19990328 Initial release
13 *
14 * Future plans: Simple file and path name completion. (like BASH)
15 *
16 */
17
18 /*
19 Usage and Known bugs:
20 Terminal key codes are not extensive, and more will probably
21 need to be added. This version was created on Debian GNU/Linux 2.x.
22 Delete, Backspace, Home, End, and the arrow keys were tested
23 to work in an Xterm and console. Ctrl-A also works as Home.
24 Ctrl-E also works as End. Ctrl-D and Ctrl-U perform their respective
25 functions. The binary size increase is <3K.
26
27 Editting will not display correctly for lines greater then the
28 terminal width. (more then one line.) However, history will.
29 */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <termios.h>
36 #include <ctype.h>
37 #include <sys/ioctl.h>
38
39 #include "input.h"
40 #include "output.h"
41
42 #include "hetio.h"
43
44
45 #define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */
46
47 #define ESC 27
48 #define DEL 127
49
50 static struct history *his_front = NULL; /* First element in command line list */
51 static struct history *his_end = NULL; /* Last element in command line list */
52 static struct termios old_term, new_term; /* Current termio and the previous termio before starting ash */
53
54 static int history_counter = 0; /* Number of commands in history list */
55 static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */
56 static int hetio_inter = 0;
57
58 struct history
59 {
60 char *s;
61 struct history *p;
62 struct history *n;
63 };
64
65
66 void input_delete (int);
67 void input_home (int *);
68 void input_end (int *, int);
69 void input_backspace (int *, int *);
70
71
72
73 void hetio_init(void)
74 {
75 hetio_inter = 1;
76 }
77
78
79 void hetio_reset_term(void)
80 {
81 if (reset_term)
82 tcsetattr(1, TCSANOW, &old_term);
83 }
84
85
86 void setIO(struct termios *new, struct termios *old) /* Set terminal IO to canonical mode, and save old term settings. */
87 {
88 tcgetattr(0, old);
89 memcpy(new, old, sizeof(*new));
90 new->c_cc[VMIN] = 1;
91 new->c_cc[VTIME] = 0;
92 new->c_lflag &= ~ICANON; /* unbuffered input */
93 new->c_lflag &= ~ECHO;
94 tcsetattr(0, TCSANOW, new);
95 }
96
97 void input_home(int *cursor) /* Command line input routines */
98 {
99 while (*cursor > 0) {
100 out1c('\b');
101 --*cursor;
102 }
103 flushout(out1);
104 }
105
106
107 void input_delete(int cursor)
108 {
109 int j = 0;
110
111 memmove(parsenextc + cursor, parsenextc + cursor + 1,
112 BUFSIZ - cursor - 1);
113 for (j = cursor; j < (BUFSIZ - 1); j++) {
114 if (!*(parsenextc + j))
115 break;
116 else
117 out1c(*(parsenextc + j));
118 }
119
120 out1str(" \b");
121
122 while (j-- > cursor)
123 out1c('\b');
124 flushout(out1);
125 }
126
127
128 void input_end(int *cursor, int len)
129 {
130 while (*cursor < len) {
131 out1str("\033[C");
132 ++*cursor;
133 }
134 flushout(out1);
135 }
136
137
138 void
139 input_backspace(int *cursor, int *len)
140 {
141 int j = 0;
142
143 if (*cursor > 0) {
144 out1str("\b \b");
145 --*cursor;
146 memmove(parsenextc + *cursor, parsenextc + *cursor + 1,
147 BUFSIZ - *cursor + 1);
148
149 for (j = *cursor; j < (BUFSIZ - 1); j++) {
150 if (!*(parsenextc + j))
151 break;
152 else
153 out1c(*(parsenextc + j));
154 }
155
156 out1str(" \b");
157
158 while (j-- > *cursor)
159 out1c('\b');
160
161 --*len;
162 flushout(out1);
163 }
164 }
165
166 int hetio_read_input(int fd)
167 {
168 int nr = 0;
169
170 /* Are we an interactive shell? */
171 if (!hetio_inter || fd) {
172 return -255;
173 } else {
174 int len = 0;
175 int j = 0;
176 int cursor = 0;
177 int break_out = 0;
178 int ret = 0;
179 char c = 0;
180 struct history *hp = his_end;
181
182 if (!reset_term) {
183 setIO(&new_term, &old_term);
184 reset_term = 1;
185 } else {
186 tcsetattr(0, TCSANOW, &new_term);
187 }
188
189 memset(parsenextc, 0, BUFSIZ);
190
191 while (1) {
192 if ((ret = read(fd, &c, 1)) < 1)
193 return ret;
194
195 switch (c) {
196 case 1: /* Control-A Beginning of line */
197 input_home(&cursor);
198 break;
199 case 5: /* Control-E EOL */
200 input_end(&cursor, len);
201 break;
202 case 4: /* Control-D */
203 if (!len)
204 exitshell(0);
205 break;
206 case 21: /* Control-U */
207 /* Return to begining of line. */
208 for (; cursor > 0; cursor--)
209 out1c('\b');
210 /* Erase old command. */
211 for (j = 0; j < len; j++) {
212 /*
213 * Clear buffer while we're at
214 * it.
215 */
216 parsenextc[j] = 0;
217 out1c(' ');
218 }
219 /* return to begining of line */
220 for (; len > 0; len--)
221 out1c('\b');
222 flushout(out1);
223 break;
224 case '\b': /* Backspace */
225 case DEL:
226 input_backspace(&cursor, &len);
227 break;
228 case '\n': /* Enter */
229 *(parsenextc + len++ + 1) = c;
230 out1c(c);
231 flushout(out1);
232 break_out = 1;
233 break;
234 case ESC: /* escape sequence follows */
235 if ((ret = read(fd, &c, 1)) < 1)
236 return ret;
237
238 if (c == '[' ) { /* 91 */
239 if ((ret = read(fd, &c, 1)) < 1)
240 return ret;
241
242 switch (c) {
243 case 'A':
244 if (hp && hp->p) { /* Up */
245 hp = hp->p;
246 goto hop;
247 }
248 break;
249 case 'B':
250 if (hp && hp->n && hp->n->s) { /* Down */
251 hp = hp->n;
252 goto hop;
253 }
254 break;
255
256 hop: /* hop */
257 len = strlen(parsenextc);
258
259 for (; cursor > 0; cursor--) /* return to begining of line */
260 out1c('\b');
261
262 for (j = 0; j < len; j++) /* erase old command */
263 out1c(' ');
264
265 for (; j > 0; j--) /* return to begining of line */
266 out1c('\b');
267
268 strcpy (parsenextc, hp->s); /* write new command */
269 len = strlen (hp->s);
270 out1str(parsenextc);
271 flushout(out1);
272 cursor = len;
273 break;
274 case 'C': /* Right */
275 if (cursor < len) {
276 out1str("\033[C");
277 cursor++;
278 flushout(out1);
279 }
280 break;
281 case 'D': /* Left */
282 if (cursor > 0) {
283 out1str("\033[D");
284 cursor--;
285 flushout(out1);
286 }
287 break;
288 case '3': /* Delete */
289 if (cursor != len) {
290 input_delete(cursor);
291 len--;
292 }
293 break;
294 case '1': /* Home (Ctrl-A) */
295 input_home(&cursor);
296 break;
297 case '4': /* End (Ctrl-E) */
298 input_end(&cursor, len);
299 break;
300 }
301 if (c == '1' || c == '3' || c == '4')
302 if ((ret = read(fd, &c, 1)) < 1)
303 return ret; /* read 126 (~) */
304 }
305
306 if (c == 'O') { /* 79 */
307 if ((ret = read(fd, &c, 1)) < 1)
308 return ret;
309 switch (c) {
310 case 'H': /* Home (xterm) */
311 input_home(&cursor);
312 break;
313 case 'F': /* End (xterm_ */
314 input_end(&cursor, len);
315 break;
316 }
317 }
318
319 c = 0;
320 break;
321
322 default: /* If it's regular input, do the normal thing */
323 if (!isprint(c)) /* Skip non-printable characters */
324 break;
325
326 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
327 break;
328
329 len++;
330
331 if (cursor == (len - 1)) { /* Append if at the end of the line */
332 *(parsenextc + cursor) = c;
333 } else { /* Insert otherwise */
334 memmove(parsenextc + cursor + 1, parsenextc + cursor,
335 len - cursor - 1);
336
337 *(parsenextc + cursor) = c;
338
339 for (j = cursor; j < len; j++)
340 out1c(*(parsenextc + j));
341 for (; j > cursor; j--)
342 out1str("\033[D");
343 }
344
345 cursor++;
346 out1c(c);
347 flushout(out1);
348 break;
349 }
350
351 if (break_out) /* Enter is the command terminator, no more input. */
352 break;
353 }
354
355 nr = len + 1;
356 tcsetattr(0, TCSANOW, &old_term);
357
358 if (*(parsenextc)) { /* Handle command history log */
359 struct history *h = his_end;
360
361 if (!h) { /* No previous history */
362 h = his_front = malloc(sizeof (struct history));
363 h->n = malloc(sizeof (struct history));
364 h->p = NULL;
365 h->s = strdup(parsenextc);
366
367 h->n->p = h;
368 h->n->n = NULL;
369 h->n->s = NULL;
370 his_end = h->n;
371 history_counter++;
372 } else { /* Add a new history command */
373
374 h->n = malloc(sizeof (struct history));
375
376 h->n->p = h;
377 h->n->n = NULL;
378 h->n->s = NULL;
379 h->s = strdup(parsenextc);
380 his_end = h->n;
381
382 if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */
383 struct history *p = his_front->n;
384
385 p->p = NULL;
386 free(his_front->s);
387 free(his_front);
388 his_front = p;
389 } else {
390 history_counter++;
391 }
392 }
393 }
394 }
395
396 return nr;
397 }