aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Andersen <andersen@codepoet.org>2000-03-17 01:12:41 +0000
committerErik Andersen <andersen@codepoet.org>2000-03-17 01:12:41 +0000
commit6273f655c8e5a1b7233f94fd606ceaed95b9c7a7 (patch)
treead754ea972e52bb21db4323d916bacfb4f1c3f07
parent161220c4985b8c05a57f09b2693a6cad74d2e81d (diff)
downloadbusybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.tar.gz
busybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.tar.bz2
busybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.zip
Several fixes.
-Erik
-rw-r--r--applets/busybox.c4
-rwxr-xr-xapplets/busybox.mkll3
-rwxr-xr-xapplets/busybox.sh11
-rw-r--r--busybox.c4
-rw-r--r--busybox.def.h17
-rwxr-xr-xbusybox.mkll3
-rwxr-xr-xbusybox.sh11
-rw-r--r--cmdedit.c260
-rw-r--r--kill.c13
-rw-r--r--lash.c12
-rw-r--r--procps/kill.c13
-rw-r--r--sh.c12
-rw-r--r--shell/cmdedit.c260
-rw-r--r--shell/lash.c12
-rw-r--r--utility.c5
15 files changed, 529 insertions, 111 deletions
diff --git a/applets/busybox.c b/applets/busybox.c
index 7582647d5..ee745e73e 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -4,10 +4,6 @@
4#include <string.h> 4#include <string.h>
5#include <errno.h> 5#include <errno.h>
6 6
7#ifndef BB_INIT
8#undef BB_FEATURE_LINUXRC
9#endif
10
11static int been_there_done_that = 0; 7static int been_there_done_that = 0;
12 8
13/* It has been alledged that doing such things can 9/* It has been alledged that doing such things can
diff --git a/applets/busybox.mkll b/applets/busybox.mkll
index fa1bff209..90f28e8b7 100755
--- a/applets/busybox.mkll
+++ b/applets/busybox.mkll
@@ -4,7 +4,8 @@
4DF="busybox.def.h" 4DF="busybox.def.h"
5MF="busybox.c" 5MF="busybox.c"
6 6
7LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)" 7#LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
8LIST="$(cpp $DF -dM | sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1/gp;' | sort)"
8 9
9for def in ${LIST}; do 10for def in ${LIST}; do
10 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF` 11 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
diff --git a/applets/busybox.sh b/applets/busybox.sh
index 304ac87e7..c4e241f84 100755
--- a/applets/busybox.sh
+++ b/applets/busybox.sh
@@ -1,3 +1,10 @@
1#!/bin/sh 1#!/bin/sh
2sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \ 2
3 -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h 3# I added in the extra "ls" so only source files that
4# actually exist will show up in the compile list.
5ls -1 ` \
6 cpp busybox.def.h -dM | \
7 sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
8 | tr [:upper:] [:lower:] | sort
9` 2>/dev/null | sed -e 's/\.c$/\.o/g'
10
diff --git a/busybox.c b/busybox.c
index 7582647d5..ee745e73e 100644
--- a/busybox.c
+++ b/busybox.c
@@ -4,10 +4,6 @@
4#include <string.h> 4#include <string.h>
5#include <errno.h> 5#include <errno.h>
6 6
7#ifndef BB_INIT
8#undef BB_FEATURE_LINUXRC
9#endif
10
11static int been_there_done_that = 0; 7static int been_there_done_that = 0;
12 8
13/* It has been alledged that doing such things can 9/* It has been alledged that doing such things can
diff --git a/busybox.def.h b/busybox.def.h
index d78a0efe8..cfafc29c8 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -40,6 +40,7 @@
40// Don't bother turning BB_INSMOD on. It doesn't work. 40// Don't bother turning BB_INSMOD on. It doesn't work.
41//#define BB_INSMOD 41//#define BB_INSMOD
42#define BB_KILL 42#define BB_KILL
43#define BB_KILLALL
43#define BB_KLOGD 44#define BB_KLOGD
44//#define BB_LENGTH 45//#define BB_LENGTH
45#define BB_LN 46#define BB_LN
@@ -198,11 +199,23 @@
198#define BB_MTAB 199#define BB_MTAB
199#endif 200#endif
200// 201//
201#ifdef BB_FEATURE_FULL_REGULAR_EXPRESSIONS 202#if defined BB_FEATURE_FULL_REGULAR_EXPRESSIONS && (defined BB_SED || defined BB_GREP )
202#define BB_REGEXP 203#define BB_REGEXP
203#endif 204#endif
204// 205//
205#ifdef BB_FEATURE_SH_COMMAND_EDITING 206#if defined BB_FEATURE_SH_COMMAND_EDITING && defined BB_SH
206#define BB_CMDEDIT 207#define BB_CMDEDIT
207#endif 208#endif
208// 209//
210#ifdef BB_KILLALL
211#ifndef BB_KILL
212#define BB_KILL
213#endif
214#endif
215//
216#ifdef BB_FEATURE_LINUXRC
217#ifndef BB_INIT
218#define BB_INIT
219#endif
220#endif
221//
diff --git a/busybox.mkll b/busybox.mkll
index fa1bff209..90f28e8b7 100755
--- a/busybox.mkll
+++ b/busybox.mkll
@@ -4,7 +4,8 @@
4DF="busybox.def.h" 4DF="busybox.def.h"
5MF="busybox.c" 5MF="busybox.c"
6 6
7LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)" 7#LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
8LIST="$(cpp $DF -dM | sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1/gp;' | sort)"
8 9
9for def in ${LIST}; do 10for def in ${LIST}; do
10 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF` 11 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
diff --git a/busybox.sh b/busybox.sh
index 304ac87e7..c4e241f84 100755
--- a/busybox.sh
+++ b/busybox.sh
@@ -1,3 +1,10 @@
1#!/bin/sh 1#!/bin/sh
2sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \ 2
3 -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h 3# I added in the extra "ls" so only source files that
4# actually exist will show up in the compile list.
5ls -1 ` \
6 cpp busybox.def.h -dM | \
7 sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
8 | tr [:upper:] [:lower:] | sort
9` 2>/dev/null | sed -e 's/\.c$/\.o/g'
10
diff --git a/cmdedit.c b/cmdedit.c
index d1604f1d1..314e8cd66 100644
--- a/cmdedit.c
+++ b/cmdedit.c
@@ -47,6 +47,8 @@
47 47
48#define ESC 27 48#define ESC 27
49#define DEL 127 49#define DEL 127
50#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
51#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
50 52
51static struct history *his_front = NULL; /* First element in command line list */ 53static struct history *his_front = NULL; /* First element in command line list */
52static struct history *his_end = NULL; /* Last element in command line list */ 54static struct history *his_end = NULL; /* Last element in command line list */
@@ -104,7 +106,7 @@ void cmdedit_reset_term(void)
104 xioctl(fileno(stdin), TCSETA, (void *) &old_term); 106 xioctl(fileno(stdin), TCSETA, (void *) &old_term);
105} 107}
106 108
107void gotaSignal(int sig) 109void prepareToDie(int sig)
108{ 110{
109 cmdedit_reset_term(); 111 cmdedit_reset_term();
110 fprintf(stdout, "\n"); 112 fprintf(stdout, "\n");
@@ -175,6 +177,40 @@ void input_backspace(int outputFd, int *cursor, int *len)
175 } 177 }
176} 178}
177 179
180char **username_completion_matches( char* matchBuf)
181{
182 fprintf(stderr, "\nin username_completion_matches\n");
183 return ( (char**) NULL);
184}
185char **command_completion_matches( char* matchBuf)
186{
187 fprintf(stderr, "\nin command_completion_matches\n");
188 return ( (char**) NULL);
189}
190char **directory_completion_matches( char* matchBuf)
191{
192 fprintf(stderr, "\nin directory_completion_matches\n");
193 return ( (char**) NULL);
194}
195
196/*
197 * This function is used to grab a character buffer
198 * from the input file descriptor and allows you to
199 * a string with full command editing (sortof like
200 * a mini readline).
201 *
202 * The following standard commands are not implemented:
203 * ESC-b -- Move back one word
204 * ESC-f -- Move forward one word
205 * ESC-d -- Delete back one word
206 * ESC-h -- Delete forward one word
207 * CTL-t -- Transpose two characters
208 *
209 * Furthermore, the "vi" command editing keys are not implemented.
210 *
211 * TODO: implement TAB command completion. :)
212 *
213 */
178extern int cmdedit_read_input(int inputFd, int outputFd, 214extern int cmdedit_read_input(int inputFd, int outputFd,
179 char command[BUFSIZ]) 215 char command[BUFSIZ])
180{ 216{
@@ -185,6 +221,8 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
185 int cursor = 0; 221 int cursor = 0;
186 int break_out = 0; 222 int break_out = 0;
187 int ret = 0; 223 int ret = 0;
224 int lastWasTab = FALSE;
225 char **matches = (char **)NULL;
188 char c = 0; 226 char c = 0;
189 struct history *hp = his_end; 227 struct history *hp = his_end;
190 228
@@ -209,90 +247,233 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
209 247
210 if ((ret = read(inputFd, &c, 1)) < 1) 248 if ((ret = read(inputFd, &c, 1)) < 1)
211 return ret; 249 return ret;
212 250
213 switch (c) { 251 switch (c) {
214 case 1: /* Control-A Beginning of line */ 252 case 1:
253 /* Control-a -- Beginning of line */
215 input_home(outputFd, &cursor); 254 input_home(outputFd, &cursor);
216 break; 255 case 5:
217 case 5: /* Control-E EOL */ 256 /* Control-e -- End of line */
218 input_end(outputFd, &cursor, len); 257 input_end(outputFd, &cursor, len);
219 break; 258 break;
220 case 4: /* Control-D */ 259 case 2:
260 /* Control-b -- Move back one character */
261 if (cursor > 0) {
262 xwrite(outputFd, "\033[D", 3);
263 cursor--;
264 }
265 break;
266 case 6:
267 /* Control-f -- Move forward one character */
268 if (cursor < len) {
269 xwrite(outputFd, "\033[C", 3);
270 cursor++;
271 }
272 break;
273 case 4:
274 /* Control-d -- Delete one character */
221 if (cursor != len) { 275 if (cursor != len) {
222 input_delete(outputFd, cursor); 276 input_delete(outputFd, cursor);
223 len--; 277 len--;
278 } else if (len == 0) {
279 prepareToDie(0);
280 exit(0);
281 }
282 break;
283 case 14:
284 /* Control-n -- Get next command */
285 if (hp && hp->n && hp->n->s) {
286 free( hp->s);
287 hp->s = strdup(parsenextc);
288 hp = hp->n;
289 goto hop;
224 } 290 }
225 break; 291 break;
226 case '\b': /* Backspace */ 292 case 16:
293 /* Control-p -- Get previous command */
294 if (hp && hp->p) {
295 free( hp->s);
296 hp->s = strdup(parsenextc);
297 hp = hp->p;
298 goto hop;
299 }
300 break;
301 case '\t':
302 {
303 /* Do TAB completion */
304 int in_command_position=0, ti=len-1;
305
306 if (lastWasTab == FALSE) {
307 char *tmp;
308 char *matchBuf;
309
310 if (matches) {
311 free(matches);
312 matches = (char **)NULL;
313 }
314
315 matchBuf = (char *) calloc(BUFSIZ, sizeof(char));
316
317 /* Make a local copy of the string -- up
318 * to the the position of the cursor */
319 strcpy( matchBuf, parsenextc);
320 matchBuf[cursor+1] = '\0';
321
322 /* skip leading white space */
323 tmp = matchBuf;
324 while (*tmp && isspace(*tmp)) {
325 (tmp)++;
326 ti++;
327 }
328
329 /* Determine if this is a command word or not */
330 //while ((ti > -1) && (whitespace (matchBuf[ti]))) {
331//printf("\nti=%d\n", ti);
332 // ti--;
333 // }
334printf("\nti=%d\n", ti);
335
336 if (ti < 0) {
337 in_command_position++;
338 } else if (member(matchBuf[ti], ";|&{(`")) {
339 int this_char, prev_char;
340 in_command_position++;
341 /* Handle the two character tokens `>&', `<&', and `>|'.
342 We are not in a command position after one of these. */
343 this_char = matchBuf[ti];
344 prev_char = matchBuf[ti - 1];
345
346 if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
347 (this_char == '|' && prev_char == '>')) {
348 in_command_position = 0;
349 }
350 /* For now, do not bother with catching quoted
351 * expressions and marking them as not in command
352 * positions. Some other day. Or not.
353 */
354 //else if (char_is_quoted (matchBuf, ti)) {
355 // in_command_position = 0;
356 //}
357 }
358printf("\nin_command_position=%d\n", in_command_position);
359 /* If the word starts in `~', and there is no slash in the word,
360 * then try completing this word as a username. */
361 if (*matchBuf == '~' && !strchr (matchBuf, '/'))
362 matches = username_completion_matches(matchBuf);
363
364 /* If this word is in a command position, then complete over possible
365 * command names, including aliases, built-ins, and executables. */
366 if (!matches && in_command_position) {
367 matches = command_completion_matches(matchBuf);
368
369 /* If we are attempting command completion and nothing matches,
370 * then try and match directories as a last resort... */
371 if (!matches)
372 matches = directory_completion_matches(matchBuf);
373 }
374 } else {
375 printf("\nprinting match list\n");
376 }
377 /* Rewrite the whole line (for debugging) */
378 for (; cursor > 0; cursor--)
379 xwrite(outputFd, "\b", 1);
380 len = strlen(parsenextc);
381 xwrite(outputFd, parsenextc, len);
382 cursor = len;
383 break;
384 }
385 case '\b':
227 case DEL: 386 case DEL:
387 /* Backspace */
228 input_backspace(outputFd, &cursor, &len); 388 input_backspace(outputFd, &cursor, &len);
229 break; 389 break;
230 case '\n': /* Enter */ 390 case '\n':
391 /* Enter */
231 *(parsenextc + len++ + 1) = c; 392 *(parsenextc + len++ + 1) = c;
232 xwrite(outputFd, &c, 1); 393 xwrite(outputFd, &c, 1);
233 break_out = 1; 394 break_out = 1;
234 break; 395 break;
235 case ESC: /* escape sequence follows */ 396 case ESC: {
397 /* escape sequence follows */
236 if ((ret = read(inputFd, &c, 1)) < 1) 398 if ((ret = read(inputFd, &c, 1)) < 1)
237 return ret; 399 return ret;
238 400
239 if (c == '[') { /* 91 */ 401 if (c == '[') { /* 91 */
240 if ((ret = read(inputFd, &c, 1)) < 1) 402 if ((ret = read(inputFd, &c, 1)) < 1)
241 return ret; 403 return ret;
242 404
243 switch (c) { 405 switch (c) {
244 case 'A': 406 case 'A':
245 if (hp && hp->p) { /* Up */ 407 /* Up Arrow -- Get previous command */
408 if (hp && hp->p) {
409 free( hp->s);
410 hp->s = strdup(parsenextc);
246 hp = hp->p; 411 hp = hp->p;
247 goto hop; 412 goto hop;
248 } 413 }
249 break; 414 break;
250 case 'B': 415 case 'B':
251 if (hp && hp->n && hp->n->s) { /* Down */ 416 /* Down Arrow -- Get next command */
417 if (hp && hp->n && hp->n->s) {
418 free( hp->s);
419 hp->s = strdup(parsenextc);
252 hp = hp->n; 420 hp = hp->n;
253 goto hop; 421 goto hop;
254 } 422 }
255 break; 423 break;
256 424
257 hop: /* hop */ 425 /* This is where we rewrite the line
426 * using the selected history item */
427 hop:
258 len = strlen(parsenextc); 428 len = strlen(parsenextc);
259 429
260 for (; cursor > 0; cursor--) /* return to begining of line */ 430 /* return to begining of line */
431 for (; cursor > 0; cursor--)
261 xwrite(outputFd, "\b", 1); 432 xwrite(outputFd, "\b", 1);
433 xwrite(outputFd, parsenextc, len);
262 434
263 for (j = 0; j < len; j++) /* erase old command */ 435 /* erase old command */
436 for (j = 0; j < len; j++)
264 xwrite(outputFd, " ", 1); 437 xwrite(outputFd, " ", 1);
265 438
266 for (j = len; j > 0; j--) /* return to begining of line */ 439 /* return to begining of line */
440 for (j = len; j > 0; j--)
267 xwrite(outputFd, "\b", 1); 441 xwrite(outputFd, "\b", 1);
268 442
269 strcpy(parsenextc, hp->s); /* write new command */ 443 memset(parsenextc, 0, BUFSIZ);
444 /* write new command */
445 strcpy(parsenextc, hp->s);
270 len = strlen(hp->s); 446 len = strlen(hp->s);
271 xwrite(outputFd, parsenextc, len); 447 xwrite(outputFd, parsenextc, len);
272 cursor = len; 448 cursor = len;
273 break; 449 break;
274 case 'C': /* Right */ 450 case 'C':
451 /* Right Arrow -- Move forward one character */
275 if (cursor < len) { 452 if (cursor < len) {
276 xwrite(outputFd, "\033[C", 3); 453 xwrite(outputFd, "\033[C", 3);
277 cursor++; 454 cursor++;
278 } 455 }
279 break; 456 break;
280 case 'D': /* Left */ 457 case 'D':
458 /* Left Arrow -- Move back one character */
281 if (cursor > 0) { 459 if (cursor > 0) {
282 xwrite(outputFd, "\033[D", 3); 460 xwrite(outputFd, "\033[D", 3);
283 cursor--; 461 cursor--;
284 } 462 }
285 break; 463 break;
286 case '3': /* Delete */ 464 case '3':
465 /* Delete */
287 if (cursor != len) { 466 if (cursor != len) {
288 input_delete(outputFd, cursor); 467 input_delete(outputFd, cursor);
289 len--; 468 len--;
290 } 469 }
291 break; 470 break;
292 case '1': /* Home (Ctrl-A) */ 471 case '1':
472 /* Home (Ctrl-A) */
293 input_home(outputFd, &cursor); 473 input_home(outputFd, &cursor);
294 break; 474 break;
295 case '4': /* End (Ctrl-E) */ 475 case '4':
476 /* End (Ctrl-E) */
296 input_end(outputFd, &cursor, len); 477 input_end(outputFd, &cursor, len);
297 break; 478 break;
298 } 479 }
@@ -300,20 +481,24 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
300 if ((ret = read(inputFd, &c, 1)) < 1) 481 if ((ret = read(inputFd, &c, 1)) < 1)
301 return ret; /* read 126 (~) */ 482 return ret; /* read 126 (~) */
302 } 483 }
303 if (c == 'O') { /* 79 */ 484 if (c == 'O') {
485 /* 79 */
304 if ((ret = read(inputFd, &c, 1)) < 1) 486 if ((ret = read(inputFd, &c, 1)) < 1)
305 return ret; 487 return ret;
306 switch (c) { 488 switch (c) {
307 case 'H': /* Home (xterm) */ 489 case 'H':
490 /* Home (xterm) */
308 input_home(outputFd, &cursor); 491 input_home(outputFd, &cursor);
309 break; 492 break;
310 case 'F': /* End (xterm) */ 493 case 'F':
494 /* End (xterm) */
311 input_end(outputFd, &cursor, len); 495 input_end(outputFd, &cursor, len);
312 break; 496 break;
313 } 497 }
314 } 498 }
315 c = 0; 499 c = 0;
316 break; 500 break;
501 }
317 502
318 default: /* If it's regular input, do the normal thing */ 503 default: /* If it's regular input, do the normal thing */
319 504
@@ -343,6 +528,10 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
343 xwrite(outputFd, &c, 1); 528 xwrite(outputFd, &c, 1);
344 break; 529 break;
345 } 530 }
531 if (c=='\t')
532 lastWasTab = TRUE;
533 else
534 lastWasTab = FALSE;
346 535
347 if (break_out) /* Enter is the command terminator, no more input. */ 536 if (break_out) /* Enter is the command terminator, no more input. */
348 break; 537 break;
@@ -353,32 +542,33 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
353 reset_term = 0; 542 reset_term = 0;
354 543
355 544
356 if (*(parsenextc)) { /* Handle command history log */ 545 /* Handle command history log */
546 if (*(parsenextc)) {
357 547
358 struct history *h = his_end; 548 struct history *h = his_end;
359 549
360 if (!h) { /* No previous history */ 550 if (!h) {
551 /* No previous history */
361 h = his_front = malloc(sizeof(struct history)); 552 h = his_front = malloc(sizeof(struct history));
362 h->n = malloc(sizeof(struct history)); 553 h->n = malloc(sizeof(struct history));
363 h->p = NULL; 554 h->p = NULL;
364 h->s = strdup(parsenextc); 555 h->s = strdup(parsenextc);
365
366 h->n->p = h; 556 h->n->p = h;
367 h->n->n = NULL; 557 h->n->n = NULL;
368 h->n->s = NULL; 558 h->n->s = NULL;
369 his_end = h->n; 559 his_end = h->n;
370 history_counter++; 560 history_counter++;
371 } else { /* Add a new history command */ 561 } else {
372 562 /* Add a new history command */
373 h->n = malloc(sizeof(struct history)); 563 h->n = malloc(sizeof(struct history));
374
375 h->n->p = h; 564 h->n->p = h;
376 h->n->n = NULL; 565 h->n->n = NULL;
377 h->n->s = NULL; 566 h->n->s = NULL;
378 h->s = strdup(parsenextc); 567 h->s = strdup(parsenextc);
379 his_end = h->n; 568 his_end = h->n;
380 569
381 if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */ 570 /* After max history, remove the oldest command */
571 if (history_counter >= MAX_HISTORY) {
382 572
383 struct history *p = his_front->n; 573 struct history *p = his_front->n;
384 574
@@ -398,8 +588,8 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
398extern void cmdedit_init(void) 588extern void cmdedit_init(void)
399{ 589{
400 atexit(cmdedit_reset_term); 590 atexit(cmdedit_reset_term);
401 signal(SIGINT, gotaSignal); 591 signal(SIGINT, prepareToDie);
402 signal(SIGQUIT, gotaSignal); 592 signal(SIGQUIT, prepareToDie);
403 signal(SIGTERM, gotaSignal); 593 signal(SIGTERM, prepareToDie);
404} 594}
405#endif /* BB_FEATURE_SH_COMMAND_EDITING */ 595#endif /* BB_FEATURE_SH_COMMAND_EDITING */
diff --git a/kill.c b/kill.c
index 8a99e0f9e..10343a150 100644
--- a/kill.c
+++ b/kill.c
@@ -36,11 +36,12 @@ static const char *kill_usage =
36 "Send a signal (default is SIGTERM) to the specified process(es).\n\n" 36 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"
37 "Options:\n" "\t-l\tList all signal names and numbers.\n\n"; 37 "Options:\n" "\t-l\tList all signal names and numbers.\n\n";
38 38
39#ifdef BB_KILLALL
39static const char *killall_usage = 40static const char *killall_usage =
40 "killall [-signal] process-name [process-name ...]\n\n" 41 "killall [-signal] process-name [process-name ...]\n\n"
41 "Send a signal (default is SIGTERM) to the specified process(es).\n\n" 42 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"
42 "Options:\n" "\t-l\tList all signal names and numbers.\n\n"; 43 "Options:\n" "\t-l\tList all signal names and numbers.\n\n";
43 44#endif
44 45
45#define KILL 0 46#define KILL 0
46#define KILLALL 1 47#define KILLALL 1
@@ -132,10 +133,15 @@ extern int kill_main(int argc, char **argv)
132 int whichApp, sig = SIGTERM; 133 int whichApp, sig = SIGTERM;
133 const char *appUsage; 134 const char *appUsage;
134 135
136#ifdef BB_KILLALL
135 /* Figure out what we are trying to do here */ 137 /* Figure out what we are trying to do here */
136 whichApp = (strcmp(*argv, "killall") == 0)? 138 whichApp = (strcmp(*argv, "killall") == 0)?
137 KILLALL : KILL; 139 KILLALL : KILL;
138 appUsage = (whichApp == KILLALL)? killall_usage : kill_usage; 140 appUsage = (whichApp == KILLALL)? killall_usage : kill_usage;
141#else
142 whichApp = KILL;
143 appUsage = kill_usage;
144#endif
139 145
140 argc--; 146 argc--;
141 argv++; 147 argv++;
@@ -213,7 +219,9 @@ extern int kill_main(int argc, char **argv)
213 fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno)); 219 fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
214 argv++; 220 argv++;
215 } 221 }
216 } else { 222 }
223#ifdef BB_KILLALL
224 else {
217 /* Looks like they want to do a killall. Do that */ 225 /* Looks like they want to do a killall. Do that */
218 while (--argc >= 0) { 226 while (--argc >= 0) {
219 int pid; 227 int pid;
@@ -225,6 +233,7 @@ extern int kill_main(int argc, char **argv)
225 argv++; 233 argv++;
226 } 234 }
227 } 235 }
236#endif
228 237
229 exit(TRUE); 238 exit(TRUE);
230 239
diff --git a/lash.c b/lash.c
index e143cfe74..068159697 100644
--- a/lash.c
+++ b/lash.c
@@ -98,7 +98,7 @@ static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
98static int shell_help(struct job *cmd, struct jobSet *junk); 98static int shell_help(struct job *cmd, struct jobSet *junk);
99static int shell_jobs(struct job *dummy, struct jobSet *jobList); 99static int shell_jobs(struct job *dummy, struct jobSet *jobList);
100static int shell_pwd(struct job *dummy, struct jobSet *junk); 100static int shell_pwd(struct job *dummy, struct jobSet *junk);
101static int shell_set(struct job *cmd, struct jobSet *junk); 101static int shell_export(struct job *cmd, struct jobSet *junk);
102static int shell_source(struct job *cmd, struct jobSet *jobList); 102static int shell_source(struct job *cmd, struct jobSet *jobList);
103static int shell_unset(struct job *cmd, struct jobSet *junk); 103static int shell_unset(struct job *cmd, struct jobSet *junk);
104 104
@@ -120,7 +120,7 @@ static struct builtInCommand bltins[] = {
120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
121 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 121 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
122 {"pwd", "Print current directory", "pwd", shell_pwd}, 122 {"pwd", "Print current directory", "pwd", shell_pwd},
123 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 123 {"export", "Set environment variable", "export [VAR=value]", shell_export},
124 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 124 {"unset", "Unset environment variable", "unset VAR", shell_unset},
125 125
126 {".", "Source-in and run commands in a file", ". filename", 126 {".", "Source-in and run commands in a file", ". filename",
@@ -182,7 +182,7 @@ static int shell_exit(struct job *cmd, struct jobSet *junk)
182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) 182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
183{ 183{
184 int i, jobNum; 184 int i, jobNum;
185 struct job *job; 185 struct job *job=NULL;
186 186
187 if (!jobList->head) { 187 if (!jobList->head) {
188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
@@ -268,8 +268,8 @@ static int shell_pwd(struct job *dummy, struct jobSet *junk)
268 return TRUE; 268 return TRUE;
269} 269}
270 270
271/* built-in 'set VAR=value' handler */ 271/* built-in 'export VAR=value' handler */
272static int shell_set(struct job *cmd, struct jobSet *junk) 272static int shell_export(struct job *cmd, struct jobSet *junk)
273{ 273{
274 int res; 274 int res;
275 275
@@ -278,7 +278,7 @@ static int shell_set(struct job *cmd, struct jobSet *junk)
278 } 278 }
279 res = putenv(cmd->progs[0].argv[1]); 279 res = putenv(cmd->progs[0].argv[1]);
280 if (res) 280 if (res)
281 fprintf(stdout, "set: %s\n", strerror(errno)); 281 fprintf(stdout, "export: %s\n", strerror(errno));
282 return (res); 282 return (res);
283} 283}
284 284
diff --git a/procps/kill.c b/procps/kill.c
index 8a99e0f9e..10343a150 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -36,11 +36,12 @@ static const char *kill_usage =
36 "Send a signal (default is SIGTERM) to the specified process(es).\n\n" 36 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"
37 "Options:\n" "\t-l\tList all signal names and numbers.\n\n"; 37 "Options:\n" "\t-l\tList all signal names and numbers.\n\n";
38 38
39#ifdef BB_KILLALL
39static const char *killall_usage = 40static const char *killall_usage =
40 "killall [-signal] process-name [process-name ...]\n\n" 41 "killall [-signal] process-name [process-name ...]\n\n"
41 "Send a signal (default is SIGTERM) to the specified process(es).\n\n" 42 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"
42 "Options:\n" "\t-l\tList all signal names and numbers.\n\n"; 43 "Options:\n" "\t-l\tList all signal names and numbers.\n\n";
43 44#endif
44 45
45#define KILL 0 46#define KILL 0
46#define KILLALL 1 47#define KILLALL 1
@@ -132,10 +133,15 @@ extern int kill_main(int argc, char **argv)
132 int whichApp, sig = SIGTERM; 133 int whichApp, sig = SIGTERM;
133 const char *appUsage; 134 const char *appUsage;
134 135
136#ifdef BB_KILLALL
135 /* Figure out what we are trying to do here */ 137 /* Figure out what we are trying to do here */
136 whichApp = (strcmp(*argv, "killall") == 0)? 138 whichApp = (strcmp(*argv, "killall") == 0)?
137 KILLALL : KILL; 139 KILLALL : KILL;
138 appUsage = (whichApp == KILLALL)? killall_usage : kill_usage; 140 appUsage = (whichApp == KILLALL)? killall_usage : kill_usage;
141#else
142 whichApp = KILL;
143 appUsage = kill_usage;
144#endif
139 145
140 argc--; 146 argc--;
141 argv++; 147 argv++;
@@ -213,7 +219,9 @@ extern int kill_main(int argc, char **argv)
213 fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno)); 219 fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
214 argv++; 220 argv++;
215 } 221 }
216 } else { 222 }
223#ifdef BB_KILLALL
224 else {
217 /* Looks like they want to do a killall. Do that */ 225 /* Looks like they want to do a killall. Do that */
218 while (--argc >= 0) { 226 while (--argc >= 0) {
219 int pid; 227 int pid;
@@ -225,6 +233,7 @@ extern int kill_main(int argc, char **argv)
225 argv++; 233 argv++;
226 } 234 }
227 } 235 }
236#endif
228 237
229 exit(TRUE); 238 exit(TRUE);
230 239
diff --git a/sh.c b/sh.c
index e143cfe74..068159697 100644
--- a/sh.c
+++ b/sh.c
@@ -98,7 +98,7 @@ static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
98static int shell_help(struct job *cmd, struct jobSet *junk); 98static int shell_help(struct job *cmd, struct jobSet *junk);
99static int shell_jobs(struct job *dummy, struct jobSet *jobList); 99static int shell_jobs(struct job *dummy, struct jobSet *jobList);
100static int shell_pwd(struct job *dummy, struct jobSet *junk); 100static int shell_pwd(struct job *dummy, struct jobSet *junk);
101static int shell_set(struct job *cmd, struct jobSet *junk); 101static int shell_export(struct job *cmd, struct jobSet *junk);
102static int shell_source(struct job *cmd, struct jobSet *jobList); 102static int shell_source(struct job *cmd, struct jobSet *jobList);
103static int shell_unset(struct job *cmd, struct jobSet *junk); 103static int shell_unset(struct job *cmd, struct jobSet *junk);
104 104
@@ -120,7 +120,7 @@ static struct builtInCommand bltins[] = {
120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
121 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 121 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
122 {"pwd", "Print current directory", "pwd", shell_pwd}, 122 {"pwd", "Print current directory", "pwd", shell_pwd},
123 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 123 {"export", "Set environment variable", "export [VAR=value]", shell_export},
124 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 124 {"unset", "Unset environment variable", "unset VAR", shell_unset},
125 125
126 {".", "Source-in and run commands in a file", ". filename", 126 {".", "Source-in and run commands in a file", ". filename",
@@ -182,7 +182,7 @@ static int shell_exit(struct job *cmd, struct jobSet *junk)
182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) 182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
183{ 183{
184 int i, jobNum; 184 int i, jobNum;
185 struct job *job; 185 struct job *job=NULL;
186 186
187 if (!jobList->head) { 187 if (!jobList->head) {
188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
@@ -268,8 +268,8 @@ static int shell_pwd(struct job *dummy, struct jobSet *junk)
268 return TRUE; 268 return TRUE;
269} 269}
270 270
271/* built-in 'set VAR=value' handler */ 271/* built-in 'export VAR=value' handler */
272static int shell_set(struct job *cmd, struct jobSet *junk) 272static int shell_export(struct job *cmd, struct jobSet *junk)
273{ 273{
274 int res; 274 int res;
275 275
@@ -278,7 +278,7 @@ static int shell_set(struct job *cmd, struct jobSet *junk)
278 } 278 }
279 res = putenv(cmd->progs[0].argv[1]); 279 res = putenv(cmd->progs[0].argv[1]);
280 if (res) 280 if (res)
281 fprintf(stdout, "set: %s\n", strerror(errno)); 281 fprintf(stdout, "export: %s\n", strerror(errno));
282 return (res); 282 return (res);
283} 283}
284 284
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index d1604f1d1..314e8cd66 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -47,6 +47,8 @@
47 47
48#define ESC 27 48#define ESC 27
49#define DEL 127 49#define DEL 127
50#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
51#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
50 52
51static struct history *his_front = NULL; /* First element in command line list */ 53static struct history *his_front = NULL; /* First element in command line list */
52static struct history *his_end = NULL; /* Last element in command line list */ 54static struct history *his_end = NULL; /* Last element in command line list */
@@ -104,7 +106,7 @@ void cmdedit_reset_term(void)
104 xioctl(fileno(stdin), TCSETA, (void *) &old_term); 106 xioctl(fileno(stdin), TCSETA, (void *) &old_term);
105} 107}
106 108
107void gotaSignal(int sig) 109void prepareToDie(int sig)
108{ 110{
109 cmdedit_reset_term(); 111 cmdedit_reset_term();
110 fprintf(stdout, "\n"); 112 fprintf(stdout, "\n");
@@ -175,6 +177,40 @@ void input_backspace(int outputFd, int *cursor, int *len)
175 } 177 }
176} 178}
177 179
180char **username_completion_matches( char* matchBuf)
181{
182 fprintf(stderr, "\nin username_completion_matches\n");
183 return ( (char**) NULL);
184}
185char **command_completion_matches( char* matchBuf)
186{
187 fprintf(stderr, "\nin command_completion_matches\n");
188 return ( (char**) NULL);
189}
190char **directory_completion_matches( char* matchBuf)
191{
192 fprintf(stderr, "\nin directory_completion_matches\n");
193 return ( (char**) NULL);
194}
195
196/*
197 * This function is used to grab a character buffer
198 * from the input file descriptor and allows you to
199 * a string with full command editing (sortof like
200 * a mini readline).
201 *
202 * The following standard commands are not implemented:
203 * ESC-b -- Move back one word
204 * ESC-f -- Move forward one word
205 * ESC-d -- Delete back one word
206 * ESC-h -- Delete forward one word
207 * CTL-t -- Transpose two characters
208 *
209 * Furthermore, the "vi" command editing keys are not implemented.
210 *
211 * TODO: implement TAB command completion. :)
212 *
213 */
178extern int cmdedit_read_input(int inputFd, int outputFd, 214extern int cmdedit_read_input(int inputFd, int outputFd,
179 char command[BUFSIZ]) 215 char command[BUFSIZ])
180{ 216{
@@ -185,6 +221,8 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
185 int cursor = 0; 221 int cursor = 0;
186 int break_out = 0; 222 int break_out = 0;
187 int ret = 0; 223 int ret = 0;
224 int lastWasTab = FALSE;
225 char **matches = (char **)NULL;
188 char c = 0; 226 char c = 0;
189 struct history *hp = his_end; 227 struct history *hp = his_end;
190 228
@@ -209,90 +247,233 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
209 247
210 if ((ret = read(inputFd, &c, 1)) < 1) 248 if ((ret = read(inputFd, &c, 1)) < 1)
211 return ret; 249 return ret;
212 250
213 switch (c) { 251 switch (c) {
214 case 1: /* Control-A Beginning of line */ 252 case 1:
253 /* Control-a -- Beginning of line */
215 input_home(outputFd, &cursor); 254 input_home(outputFd, &cursor);
216 break; 255 case 5:
217 case 5: /* Control-E EOL */ 256 /* Control-e -- End of line */
218 input_end(outputFd, &cursor, len); 257 input_end(outputFd, &cursor, len);
219 break; 258 break;
220 case 4: /* Control-D */ 259 case 2:
260 /* Control-b -- Move back one character */
261 if (cursor > 0) {
262 xwrite(outputFd, "\033[D", 3);
263 cursor--;
264 }
265 break;
266 case 6:
267 /* Control-f -- Move forward one character */
268 if (cursor < len) {
269 xwrite(outputFd, "\033[C", 3);
270 cursor++;
271 }
272 break;
273 case 4:
274 /* Control-d -- Delete one character */
221 if (cursor != len) { 275 if (cursor != len) {
222 input_delete(outputFd, cursor); 276 input_delete(outputFd, cursor);
223 len--; 277 len--;
278 } else if (len == 0) {
279 prepareToDie(0);
280 exit(0);
281 }
282 break;
283 case 14:
284 /* Control-n -- Get next command */
285 if (hp && hp->n && hp->n->s) {
286 free( hp->s);
287 hp->s = strdup(parsenextc);
288 hp = hp->n;
289 goto hop;
224 } 290 }
225 break; 291 break;
226 case '\b': /* Backspace */ 292 case 16:
293 /* Control-p -- Get previous command */
294 if (hp && hp->p) {
295 free( hp->s);
296 hp->s = strdup(parsenextc);
297 hp = hp->p;
298 goto hop;
299 }
300 break;
301 case '\t':
302 {
303 /* Do TAB completion */
304 int in_command_position=0, ti=len-1;
305
306 if (lastWasTab == FALSE) {
307 char *tmp;
308 char *matchBuf;
309
310 if (matches) {
311 free(matches);
312 matches = (char **)NULL;
313 }
314
315 matchBuf = (char *) calloc(BUFSIZ, sizeof(char));
316
317 /* Make a local copy of the string -- up
318 * to the the position of the cursor */
319 strcpy( matchBuf, parsenextc);
320 matchBuf[cursor+1] = '\0';
321
322 /* skip leading white space */
323 tmp = matchBuf;
324 while (*tmp && isspace(*tmp)) {
325 (tmp)++;
326 ti++;
327 }
328
329 /* Determine if this is a command word or not */
330 //while ((ti > -1) && (whitespace (matchBuf[ti]))) {
331//printf("\nti=%d\n", ti);
332 // ti--;
333 // }
334printf("\nti=%d\n", ti);
335
336 if (ti < 0) {
337 in_command_position++;
338 } else if (member(matchBuf[ti], ";|&{(`")) {
339 int this_char, prev_char;
340 in_command_position++;
341 /* Handle the two character tokens `>&', `<&', and `>|'.
342 We are not in a command position after one of these. */
343 this_char = matchBuf[ti];
344 prev_char = matchBuf[ti - 1];
345
346 if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
347 (this_char == '|' && prev_char == '>')) {
348 in_command_position = 0;
349 }
350 /* For now, do not bother with catching quoted
351 * expressions and marking them as not in command
352 * positions. Some other day. Or not.
353 */
354 //else if (char_is_quoted (matchBuf, ti)) {
355 // in_command_position = 0;
356 //}
357 }
358printf("\nin_command_position=%d\n", in_command_position);
359 /* If the word starts in `~', and there is no slash in the word,
360 * then try completing this word as a username. */
361 if (*matchBuf == '~' && !strchr (matchBuf, '/'))
362 matches = username_completion_matches(matchBuf);
363
364 /* If this word is in a command position, then complete over possible
365 * command names, including aliases, built-ins, and executables. */
366 if (!matches && in_command_position) {
367 matches = command_completion_matches(matchBuf);
368
369 /* If we are attempting command completion and nothing matches,
370 * then try and match directories as a last resort... */
371 if (!matches)
372 matches = directory_completion_matches(matchBuf);
373 }
374 } else {
375 printf("\nprinting match list\n");
376 }
377 /* Rewrite the whole line (for debugging) */
378 for (; cursor > 0; cursor--)
379 xwrite(outputFd, "\b", 1);
380 len = strlen(parsenextc);
381 xwrite(outputFd, parsenextc, len);
382 cursor = len;
383 break;
384 }
385 case '\b':
227 case DEL: 386 case DEL:
387 /* Backspace */
228 input_backspace(outputFd, &cursor, &len); 388 input_backspace(outputFd, &cursor, &len);
229 break; 389 break;
230 case '\n': /* Enter */ 390 case '\n':
391 /* Enter */
231 *(parsenextc + len++ + 1) = c; 392 *(parsenextc + len++ + 1) = c;
232 xwrite(outputFd, &c, 1); 393 xwrite(outputFd, &c, 1);
233 break_out = 1; 394 break_out = 1;
234 break; 395 break;
235 case ESC: /* escape sequence follows */ 396 case ESC: {
397 /* escape sequence follows */
236 if ((ret = read(inputFd, &c, 1)) < 1) 398 if ((ret = read(inputFd, &c, 1)) < 1)
237 return ret; 399 return ret;
238 400
239 if (c == '[') { /* 91 */ 401 if (c == '[') { /* 91 */
240 if ((ret = read(inputFd, &c, 1)) < 1) 402 if ((ret = read(inputFd, &c, 1)) < 1)
241 return ret; 403 return ret;
242 404
243 switch (c) { 405 switch (c) {
244 case 'A': 406 case 'A':
245 if (hp && hp->p) { /* Up */ 407 /* Up Arrow -- Get previous command */
408 if (hp && hp->p) {
409 free( hp->s);
410 hp->s = strdup(parsenextc);
246 hp = hp->p; 411 hp = hp->p;
247 goto hop; 412 goto hop;
248 } 413 }
249 break; 414 break;
250 case 'B': 415 case 'B':
251 if (hp && hp->n && hp->n->s) { /* Down */ 416 /* Down Arrow -- Get next command */
417 if (hp && hp->n && hp->n->s) {
418 free( hp->s);
419 hp->s = strdup(parsenextc);
252 hp = hp->n; 420 hp = hp->n;
253 goto hop; 421 goto hop;
254 } 422 }
255 break; 423 break;
256 424
257 hop: /* hop */ 425 /* This is where we rewrite the line
426 * using the selected history item */
427 hop:
258 len = strlen(parsenextc); 428 len = strlen(parsenextc);
259 429
260 for (; cursor > 0; cursor--) /* return to begining of line */ 430 /* return to begining of line */
431 for (; cursor > 0; cursor--)
261 xwrite(outputFd, "\b", 1); 432 xwrite(outputFd, "\b", 1);
433 xwrite(outputFd, parsenextc, len);
262 434
263 for (j = 0; j < len; j++) /* erase old command */ 435 /* erase old command */
436 for (j = 0; j < len; j++)
264 xwrite(outputFd, " ", 1); 437 xwrite(outputFd, " ", 1);
265 438
266 for (j = len; j > 0; j--) /* return to begining of line */ 439 /* return to begining of line */
440 for (j = len; j > 0; j--)
267 xwrite(outputFd, "\b", 1); 441 xwrite(outputFd, "\b", 1);
268 442
269 strcpy(parsenextc, hp->s); /* write new command */ 443 memset(parsenextc, 0, BUFSIZ);
444 /* write new command */
445 strcpy(parsenextc, hp->s);
270 len = strlen(hp->s); 446 len = strlen(hp->s);
271 xwrite(outputFd, parsenextc, len); 447 xwrite(outputFd, parsenextc, len);
272 cursor = len; 448 cursor = len;
273 break; 449 break;
274 case 'C': /* Right */ 450 case 'C':
451 /* Right Arrow -- Move forward one character */
275 if (cursor < len) { 452 if (cursor < len) {
276 xwrite(outputFd, "\033[C", 3); 453 xwrite(outputFd, "\033[C", 3);
277 cursor++; 454 cursor++;
278 } 455 }
279 break; 456 break;
280 case 'D': /* Left */ 457 case 'D':
458 /* Left Arrow -- Move back one character */
281 if (cursor > 0) { 459 if (cursor > 0) {
282 xwrite(outputFd, "\033[D", 3); 460 xwrite(outputFd, "\033[D", 3);
283 cursor--; 461 cursor--;
284 } 462 }
285 break; 463 break;
286 case '3': /* Delete */ 464 case '3':
465 /* Delete */
287 if (cursor != len) { 466 if (cursor != len) {
288 input_delete(outputFd, cursor); 467 input_delete(outputFd, cursor);
289 len--; 468 len--;
290 } 469 }
291 break; 470 break;
292 case '1': /* Home (Ctrl-A) */ 471 case '1':
472 /* Home (Ctrl-A) */
293 input_home(outputFd, &cursor); 473 input_home(outputFd, &cursor);
294 break; 474 break;
295 case '4': /* End (Ctrl-E) */ 475 case '4':
476 /* End (Ctrl-E) */
296 input_end(outputFd, &cursor, len); 477 input_end(outputFd, &cursor, len);
297 break; 478 break;
298 } 479 }
@@ -300,20 +481,24 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
300 if ((ret = read(inputFd, &c, 1)) < 1) 481 if ((ret = read(inputFd, &c, 1)) < 1)
301 return ret; /* read 126 (~) */ 482 return ret; /* read 126 (~) */
302 } 483 }
303 if (c == 'O') { /* 79 */ 484 if (c == 'O') {
485 /* 79 */
304 if ((ret = read(inputFd, &c, 1)) < 1) 486 if ((ret = read(inputFd, &c, 1)) < 1)
305 return ret; 487 return ret;
306 switch (c) { 488 switch (c) {
307 case 'H': /* Home (xterm) */ 489 case 'H':
490 /* Home (xterm) */
308 input_home(outputFd, &cursor); 491 input_home(outputFd, &cursor);
309 break; 492 break;
310 case 'F': /* End (xterm) */ 493 case 'F':
494 /* End (xterm) */
311 input_end(outputFd, &cursor, len); 495 input_end(outputFd, &cursor, len);
312 break; 496 break;
313 } 497 }
314 } 498 }
315 c = 0; 499 c = 0;
316 break; 500 break;
501 }
317 502
318 default: /* If it's regular input, do the normal thing */ 503 default: /* If it's regular input, do the normal thing */
319 504
@@ -343,6 +528,10 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
343 xwrite(outputFd, &c, 1); 528 xwrite(outputFd, &c, 1);
344 break; 529 break;
345 } 530 }
531 if (c=='\t')
532 lastWasTab = TRUE;
533 else
534 lastWasTab = FALSE;
346 535
347 if (break_out) /* Enter is the command terminator, no more input. */ 536 if (break_out) /* Enter is the command terminator, no more input. */
348 break; 537 break;
@@ -353,32 +542,33 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
353 reset_term = 0; 542 reset_term = 0;
354 543
355 544
356 if (*(parsenextc)) { /* Handle command history log */ 545 /* Handle command history log */
546 if (*(parsenextc)) {
357 547
358 struct history *h = his_end; 548 struct history *h = his_end;
359 549
360 if (!h) { /* No previous history */ 550 if (!h) {
551 /* No previous history */
361 h = his_front = malloc(sizeof(struct history)); 552 h = his_front = malloc(sizeof(struct history));
362 h->n = malloc(sizeof(struct history)); 553 h->n = malloc(sizeof(struct history));
363 h->p = NULL; 554 h->p = NULL;
364 h->s = strdup(parsenextc); 555 h->s = strdup(parsenextc);
365
366 h->n->p = h; 556 h->n->p = h;
367 h->n->n = NULL; 557 h->n->n = NULL;
368 h->n->s = NULL; 558 h->n->s = NULL;
369 his_end = h->n; 559 his_end = h->n;
370 history_counter++; 560 history_counter++;
371 } else { /* Add a new history command */ 561 } else {
372 562 /* Add a new history command */
373 h->n = malloc(sizeof(struct history)); 563 h->n = malloc(sizeof(struct history));
374
375 h->n->p = h; 564 h->n->p = h;
376 h->n->n = NULL; 565 h->n->n = NULL;
377 h->n->s = NULL; 566 h->n->s = NULL;
378 h->s = strdup(parsenextc); 567 h->s = strdup(parsenextc);
379 his_end = h->n; 568 his_end = h->n;
380 569
381 if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */ 570 /* After max history, remove the oldest command */
571 if (history_counter >= MAX_HISTORY) {
382 572
383 struct history *p = his_front->n; 573 struct history *p = his_front->n;
384 574
@@ -398,8 +588,8 @@ extern int cmdedit_read_input(int inputFd, int outputFd,
398extern void cmdedit_init(void) 588extern void cmdedit_init(void)
399{ 589{
400 atexit(cmdedit_reset_term); 590 atexit(cmdedit_reset_term);
401 signal(SIGINT, gotaSignal); 591 signal(SIGINT, prepareToDie);
402 signal(SIGQUIT, gotaSignal); 592 signal(SIGQUIT, prepareToDie);
403 signal(SIGTERM, gotaSignal); 593 signal(SIGTERM, prepareToDie);
404} 594}
405#endif /* BB_FEATURE_SH_COMMAND_EDITING */ 595#endif /* BB_FEATURE_SH_COMMAND_EDITING */
diff --git a/shell/lash.c b/shell/lash.c
index e143cfe74..068159697 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -98,7 +98,7 @@ static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
98static int shell_help(struct job *cmd, struct jobSet *junk); 98static int shell_help(struct job *cmd, struct jobSet *junk);
99static int shell_jobs(struct job *dummy, struct jobSet *jobList); 99static int shell_jobs(struct job *dummy, struct jobSet *jobList);
100static int shell_pwd(struct job *dummy, struct jobSet *junk); 100static int shell_pwd(struct job *dummy, struct jobSet *junk);
101static int shell_set(struct job *cmd, struct jobSet *junk); 101static int shell_export(struct job *cmd, struct jobSet *junk);
102static int shell_source(struct job *cmd, struct jobSet *jobList); 102static int shell_source(struct job *cmd, struct jobSet *jobList);
103static int shell_unset(struct job *cmd, struct jobSet *junk); 103static int shell_unset(struct job *cmd, struct jobSet *junk);
104 104
@@ -120,7 +120,7 @@ static struct builtInCommand bltins[] = {
120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 120 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
121 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 121 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
122 {"pwd", "Print current directory", "pwd", shell_pwd}, 122 {"pwd", "Print current directory", "pwd", shell_pwd},
123 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 123 {"export", "Set environment variable", "export [VAR=value]", shell_export},
124 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 124 {"unset", "Unset environment variable", "unset VAR", shell_unset},
125 125
126 {".", "Source-in and run commands in a file", ". filename", 126 {".", "Source-in and run commands in a file", ". filename",
@@ -182,7 +182,7 @@ static int shell_exit(struct job *cmd, struct jobSet *junk)
182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) 182static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
183{ 183{
184 int i, jobNum; 184 int i, jobNum;
185 struct job *job; 185 struct job *job=NULL;
186 186
187 if (!jobList->head) { 187 if (!jobList->head) {
188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 188 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
@@ -268,8 +268,8 @@ static int shell_pwd(struct job *dummy, struct jobSet *junk)
268 return TRUE; 268 return TRUE;
269} 269}
270 270
271/* built-in 'set VAR=value' handler */ 271/* built-in 'export VAR=value' handler */
272static int shell_set(struct job *cmd, struct jobSet *junk) 272static int shell_export(struct job *cmd, struct jobSet *junk)
273{ 273{
274 int res; 274 int res;
275 275
@@ -278,7 +278,7 @@ static int shell_set(struct job *cmd, struct jobSet *junk)
278 } 278 }
279 res = putenv(cmd->progs[0].argv[1]); 279 res = putenv(cmd->progs[0].argv[1]);
280 if (res) 280 if (res)
281 fprintf(stdout, "set: %s\n", strerror(errno)); 281 fprintf(stdout, "export: %s\n", strerror(errno));
282 return (res); 282 return (res);
283} 283}
284 284
diff --git a/utility.c b/utility.c
index 4b26a1b76..c274bfa15 100644
--- a/utility.c
+++ b/utility.c
@@ -1247,8 +1247,7 @@ extern int device_open(char *device, int mode)
1247#endif /* BB_INIT BB_SYSLOGD */ 1247#endif /* BB_INIT BB_SYSLOGD */
1248 1248
1249 1249
1250#if defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ) 1250#if defined BB_KILLALL || ( defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ))
1251
1252#ifdef BB_FEATURE_USE_DEVPS_PATCH 1251#ifdef BB_FEATURE_USE_DEVPS_PATCH
1253#include <linux/devps.h> 1252#include <linux/devps.h>
1254#endif 1253#endif
@@ -1363,7 +1362,7 @@ extern pid_t findPidByName( char* pidName)
1363 return 0; 1362 return 0;
1364} 1363}
1365#endif /* BB_FEATURE_USE_DEVPS_PATCH */ 1364#endif /* BB_FEATURE_USE_DEVPS_PATCH */
1366#endif /* BB_INIT || BB_HALT || BB_REBOOT || BB_POWEROFF */ 1365#endif /* BB_KILLALL || ( BB_FEATURE_LINUXRC && ( BB_HALT || BB_REBOOT || BB_POWEROFF )) */
1367 1366
1368#if defined BB_GUNZIP \ 1367#if defined BB_GUNZIP \
1369 || defined BB_GZIP \ 1368 || defined BB_GZIP \