diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-03-17 01:12:41 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-03-17 01:12:41 +0000 |
commit | 6273f655c8e5a1b7233f94fd606ceaed95b9c7a7 (patch) | |
tree | ad754ea972e52bb21db4323d916bacfb4f1c3f07 | |
parent | 161220c4985b8c05a57f09b2693a6cad74d2e81d (diff) | |
download | busybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.tar.gz busybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.tar.bz2 busybox-w32-6273f655c8e5a1b7233f94fd606ceaed95b9c7a7.zip |
Several fixes.
-Erik
-rw-r--r-- | applets/busybox.c | 4 | ||||
-rwxr-xr-x | applets/busybox.mkll | 3 | ||||
-rwxr-xr-x | applets/busybox.sh | 11 | ||||
-rw-r--r-- | busybox.c | 4 | ||||
-rw-r--r-- | busybox.def.h | 17 | ||||
-rwxr-xr-x | busybox.mkll | 3 | ||||
-rwxr-xr-x | busybox.sh | 11 | ||||
-rw-r--r-- | cmdedit.c | 260 | ||||
-rw-r--r-- | kill.c | 13 | ||||
-rw-r--r-- | lash.c | 12 | ||||
-rw-r--r-- | procps/kill.c | 13 | ||||
-rw-r--r-- | sh.c | 12 | ||||
-rw-r--r-- | shell/cmdedit.c | 260 | ||||
-rw-r--r-- | shell/lash.c | 12 | ||||
-rw-r--r-- | utility.c | 5 |
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 | |||
11 | static int been_there_done_that = 0; | 7 | static 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 @@ | |||
4 | DF="busybox.def.h" | 4 | DF="busybox.def.h" |
5 | MF="busybox.c" | 5 | MF="busybox.c" |
6 | 6 | ||
7 | LIST="$(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)" |
8 | LIST="$(cpp $DF -dM | sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1/gp;' | sort)" | ||
8 | 9 | ||
9 | for def in ${LIST}; do | 10 | for 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 |
2 | sed -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. | ||
5 | ls -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 | |||
@@ -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 | |||
11 | static int been_there_done_that = 0; | 7 | static 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 @@ | |||
4 | DF="busybox.def.h" | 4 | DF="busybox.def.h" |
5 | MF="busybox.c" | 5 | MF="busybox.c" |
6 | 6 | ||
7 | LIST="$(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)" |
8 | LIST="$(cpp $DF -dM | sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1/gp;' | sort)" | ||
8 | 9 | ||
9 | for def in ${LIST}; do | 10 | for 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 |
2 | sed -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. | ||
5 | ls -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 | |||
@@ -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 | ||
51 | static struct history *his_front = NULL; /* First element in command line list */ | 53 | static struct history *his_front = NULL; /* First element in command line list */ |
52 | static struct history *his_end = NULL; /* Last element in command line list */ | 54 | static 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 | ||
107 | void gotaSignal(int sig) | 109 | void 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 | ||
180 | char **username_completion_matches( char* matchBuf) | ||
181 | { | ||
182 | fprintf(stderr, "\nin username_completion_matches\n"); | ||
183 | return ( (char**) NULL); | ||
184 | } | ||
185 | char **command_completion_matches( char* matchBuf) | ||
186 | { | ||
187 | fprintf(stderr, "\nin command_completion_matches\n"); | ||
188 | return ( (char**) NULL); | ||
189 | } | ||
190 | char **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 | */ | ||
178 | extern int cmdedit_read_input(int inputFd, int outputFd, | 214 | extern 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 | // } | ||
334 | printf("\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 | } | ||
358 | printf("\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, | |||
398 | extern void cmdedit_init(void) | 588 | extern 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 */ |
@@ -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 | ||
39 | static const char *killall_usage = | 40 | static 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 | ||
@@ -98,7 +98,7 @@ static int shell_fg_bg(struct job *cmd, struct jobSet *jobList); | |||
98 | static int shell_help(struct job *cmd, struct jobSet *junk); | 98 | static int shell_help(struct job *cmd, struct jobSet *junk); |
99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); | 99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); | 100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
101 | static int shell_set(struct job *cmd, struct jobSet *junk); | 101 | static int shell_export(struct job *cmd, struct jobSet *junk); |
102 | static int shell_source(struct job *cmd, struct jobSet *jobList); | 102 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
103 | static int shell_unset(struct job *cmd, struct jobSet *junk); | 103 | static 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) | |||
182 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) | 182 | static 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 */ |
272 | static int shell_set(struct job *cmd, struct jobSet *junk) | 272 | static 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 | ||
39 | static const char *killall_usage = | 40 | static 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 | ||
@@ -98,7 +98,7 @@ static int shell_fg_bg(struct job *cmd, struct jobSet *jobList); | |||
98 | static int shell_help(struct job *cmd, struct jobSet *junk); | 98 | static int shell_help(struct job *cmd, struct jobSet *junk); |
99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); | 99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); | 100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
101 | static int shell_set(struct job *cmd, struct jobSet *junk); | 101 | static int shell_export(struct job *cmd, struct jobSet *junk); |
102 | static int shell_source(struct job *cmd, struct jobSet *jobList); | 102 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
103 | static int shell_unset(struct job *cmd, struct jobSet *junk); | 103 | static 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) | |||
182 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) | 182 | static 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 */ |
272 | static int shell_set(struct job *cmd, struct jobSet *junk) | 272 | static 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 | ||
51 | static struct history *his_front = NULL; /* First element in command line list */ | 53 | static struct history *his_front = NULL; /* First element in command line list */ |
52 | static struct history *his_end = NULL; /* Last element in command line list */ | 54 | static 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 | ||
107 | void gotaSignal(int sig) | 109 | void 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 | ||
180 | char **username_completion_matches( char* matchBuf) | ||
181 | { | ||
182 | fprintf(stderr, "\nin username_completion_matches\n"); | ||
183 | return ( (char**) NULL); | ||
184 | } | ||
185 | char **command_completion_matches( char* matchBuf) | ||
186 | { | ||
187 | fprintf(stderr, "\nin command_completion_matches\n"); | ||
188 | return ( (char**) NULL); | ||
189 | } | ||
190 | char **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 | */ | ||
178 | extern int cmdedit_read_input(int inputFd, int outputFd, | 214 | extern 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 | // } | ||
334 | printf("\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 | } | ||
358 | printf("\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, | |||
398 | extern void cmdedit_init(void) | 588 | extern 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); | |||
98 | static int shell_help(struct job *cmd, struct jobSet *junk); | 98 | static int shell_help(struct job *cmd, struct jobSet *junk); |
99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); | 99 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); | 100 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
101 | static int shell_set(struct job *cmd, struct jobSet *junk); | 101 | static int shell_export(struct job *cmd, struct jobSet *junk); |
102 | static int shell_source(struct job *cmd, struct jobSet *jobList); | 102 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
103 | static int shell_unset(struct job *cmd, struct jobSet *junk); | 103 | static 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) | |||
182 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList) | 182 | static 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 */ |
272 | static int shell_set(struct job *cmd, struct jobSet *junk) | 272 | static 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 | ||
@@ -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 \ |