Now actually with the patch <oops/>
Please consider for inclusion
1. Some small glitches in line editing were fixed
2. Whitespace cleaned up with leading tabs
3. Incorporate same features in hush as in ash, provided history
&lineediting enabled
On Wed, Aug 31, 2011 at 8:19 PM, Flemming Madsen <[email protected]> wrote:
>
> Hello
>
> Please consider the following additions to busybox, realized
> in the attached.
>
> They are currently supplied as one big patch against 1.19.0.
> All tested with valgrind on X86 + test on ARM9
>
> 1. inotifyd.c: Implement a builtin 'echo' command for simply
> outputting events on stdout. This will allow programs&scripts
> to popen() 'inotifyd echo ...' for easy inotify
> functionality without excessive fork/exec overhead.
>
> 2. ash.c: A history builtin command showing current history
>
> 3. procps.c: An 'l' option to ps without enabling full desktop option
> FEATURE_PS_LONG: Adds fields PPID, RSS, START, TIME & TTY
>
> 4. lineedit.c ash.c: Consider aliases and ash builtins in command
> completion
>
> 5. lineedit.c ash.c: Help on lineedit keycodes.
> FEATURE_EDITING_HELP: "Help on line editing (in ash help command)"
> % help
> Built-in commands:
> ------------------
> . : [ [[ alias bg break cd chdir command continue echo eval exec
> exit export false fg getopts hash help history jobs kill let
> local printf pwd read readonly return set shift source test times
> trap true type ulimit umask unalias unset wait
>
> Line editing:
> -------------------
> C-A, <Home> Move to start of line
> C-E, <End> Move to end of line
> C-B, <Left> Move back one char
> C-F, <Right> Move forward one char
> C-D Delete one char or exit
> <Del> Delete one char to the right
> C-H Delete one char to the left
> C-W Delete one Word to the left
> C-U Clear line before cursor
> C-K Kill / Clear rest of line
> C-L Clear screen
> C-R Inremental reverse history search
> C-X Redraw line
> C-P, <Up> Get previous command line
> C-N, <Down> Get next command line
> <Tab> Tab completion
> M-Tab, S-Tab Tab menu forward. <Tab> goes back again
> M-b, C-Left Move word backward
> M-f, C-Right Move word forward
> M-w, M-BkSpace Delete word backward
> M-d, M-Del Delete word forward
> M-P, M-Up Get previous line, matching prefix
> M-n, M-Down Get next line, matching prefix
> M-., M-_ Insert last word of previous line
>
> 6. lineedit.c: Support for some of the the above keycodes
> FEATURE_EDITING_EXT: "Additional Meta key line editing commands"
> Enable M-b M-f M-w M-d M-w M-n M-p and M-. M-_ editing commands
>
> a) Completion menu for browsing completion matches with S-Tab/Tab
> b) Find commands matching prefix before cursor with M-p M-n
> c) Insert last word of previous (repeated) command with M-. or M-_
> d) Word/identifier deletion and movement aliases M-w M-b M-f
> e) Redraw line with C-X (And C-R if inremental search is disabled)
>
>
> Sizes:
> ------
>
> Pristine sources:
> text data bss dec hex filename
> 500008 1876 8780 510664 7cac8 ../busybox-1.19.0/busybox
>
> +626: Non config'able changes; inotifyd echo + history + completion extra
> text data bss dec hex filename
> 500634 1876 8780 511290 7cd3a busybox
>
> +628 Lineedit help added
> text data bss dec hex filename
> 501262 1876 8780 511918 7cfae busybox
>
> +757 Ps long option added
> text data bss dec hex filename
> 502019 1876 8780 512675 7d2a3 busybox
>
> +1765 Line edit additions added
> text data bss dec hex filename
> 503784 1876 8780 514440 7d988 busybox
>
>
> Enjoy
>
> /Flemming
--- busybox-1.19.0/include/libbb.h.orig
+++ busybox-1.19.0/include/libbb.h
@@ -1352,34 +1352,42 @@
* yet doesn't represent any valid Unicode character.
* Also, -1 is reserved for error indication and we don't use it. */
enum {
- KEYCODE_UP = -2,
- KEYCODE_DOWN = -3,
- KEYCODE_RIGHT = -4,
- KEYCODE_LEFT = -5,
- KEYCODE_HOME = -6,
- KEYCODE_END = -7,
- KEYCODE_INSERT = -8,
- KEYCODE_DELETE = -9,
- KEYCODE_PAGEUP = -10,
- KEYCODE_PAGEDOWN = -11,
+ KEYCODE_UP = -2,
+ KEYCODE_DOWN = -3,
+ KEYCODE_RIGHT = -4,
+ KEYCODE_LEFT = -5,
+ KEYCODE_HOME = -6,
+ KEYCODE_END = -7,
+ KEYCODE_INSERT = -8,
+ KEYCODE_DELETE = -9,
+ KEYCODE_PAGEUP = -10,
+ KEYCODE_PAGEDOWN = -11,
+ KEYCODE_SHIFT_TAB = -12,
- KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40,
- KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40,
- KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40,
- KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40,
+ /* Using this bit reduces keycode count to 32 - Inline them above instead ? */
+ KEYCODE_ALT_UP = KEYCODE_UP & ~0x20,
+ KEYCODE_ALT_DOWN = KEYCODE_DOWN & ~0x20,
+ KEYCODE_ALT_RIGHT = KEYCODE_RIGHT & ~0x20,
+ KEYCODE_ALT_LEFT = KEYCODE_LEFT & ~0x20,
+ KEYCODE_ALT_DELETE = KEYCODE_DELETE & ~0x20,
+
+ KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40,
+ KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40,
+ KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40,
+ KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40,
#if 0
- KEYCODE_FUN1 = -12,
- KEYCODE_FUN2 = -13,
- KEYCODE_FUN3 = -14,
- KEYCODE_FUN4 = -15,
- KEYCODE_FUN5 = -16,
- KEYCODE_FUN6 = -17,
- KEYCODE_FUN7 = -18,
- KEYCODE_FUN8 = -19,
- KEYCODE_FUN9 = -20,
- KEYCODE_FUN10 = -21,
- KEYCODE_FUN11 = -22,
- KEYCODE_FUN12 = -23,
+ KEYCODE_FUN1 = -13,
+ KEYCODE_FUN2 = -14,
+ KEYCODE_FUN3 = -15,
+ KEYCODE_FUN4 = -16,
+ KEYCODE_FUN5 = -17,
+ KEYCODE_FUN6 = -18,
+ KEYCODE_FUN7 = -19,
+ KEYCODE_FUN8 = -20,
+ KEYCODE_FUN9 = -21,
+ KEYCODE_FUN10 = -22,
+ KEYCODE_FUN11 = -23,
+ KEYCODE_FUN12 = -24,
#endif
KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */
/* How long is the longest ESC sequence we know?
@@ -1416,9 +1424,12 @@
typedef struct line_input_t {
int flags;
const char *path_lookup;
+ void (*extra_cmd)(void (*add)(const char *), void*);
+ void *extra_cmd_arg;
# if MAX_HISTORY
int cnt_history;
int cur_history;
+ int cur_cmdno;
int max_history; /* must never be <= 0 */
# if ENABLE_FEATURE_EDITING_SAVEHISTORY
unsigned cnt_history_in_file;
@@ -1446,6 +1457,7 @@
* >0 length of input string, including terminating '\n'
*/
int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
+void line_input_help(void) FAST_FUNC;
#else
#define MAX_HISTORY 0
int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
--- busybox-1.19.0/libbb/Config.src.orig
+++ busybox-1.19.0/libbb/Config.src
@@ -70,6 +70,14 @@
You may want to decrease this parameter if your target machine
benefits from smaller stack usage.
+config FEATURE_EDITING_HELP
+ bool "Help on line editing (in ash help command)"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Add a routine for outputting line edit help, and use it in
+ the ash help builtin command
+
config FEATURE_EDITING_VI
bool "vi-style line editing commands"
default n
@@ -78,6 +86,15 @@
Enable vi-style line editing. In shells, this mode can be
turned on and off with "set -o vi" and "set +o vi".
+config FEATURE_EDITING_EXT
+ bool "Additional Meta key line editing commands"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Extra editing commands. Use either Alt-Key or Esc-Key
+ Enable M-b M-f M-w M-d M-w M-n M-p and M-. M-_ editing commands
+ M-n and M-p are history search back and forth.
+
config FEATURE_EDITING_HISTORY
int "History size"
# Don't allow way too big values here, code uses fixed "char *history[N]" struct member
--- busybox-1.19.0/libbb/lineedit.c.orig
+++ busybox-1.19.0/libbb/lineedit.c
@@ -145,6 +145,11 @@
#if ENABLE_FEATURE_TAB_COMPLETION
char **matches;
unsigned num_matches;
+#if ENABLE_FEATURE_EDITING_EXT
+ int cmpmenu_org_pfx;
+ int cmpmenu_curlen;
+ int cmpmenu_curpos;
+#endif
#endif
#if ENABLE_FEATURE_EDITING_VI
@@ -752,14 +757,23 @@
const char *pfind;
char *dirbuf = NULL;
+ auto void add_match_if(const char *cmd);
+ void add_match_if(const char *cmd) {
+ if (0 == strncmp(cmd, pfind, strlen(pfind)))
+ add_match(xstrdup(cmd));
+ }
+
npaths = 1;
path1[0] = (char*)".";
pfind = strrchr(command, '/');
if (!pfind) {
- if (type == FIND_EXE_ONLY)
- npaths = path_parse(&paths);
pfind = command;
+ if (type == FIND_EXE_ONLY) {
+ npaths = path_parse(&paths);
+ if (state->extra_cmd)
+ state->extra_cmd(add_match_if, state->extra_cmd_arg);
+ }
} else {
/* point to 'l' in "..../last_component" */
pfind++;
@@ -1065,19 +1079,58 @@
return s;
}
+enum {
+ TS_LAST_NOT_TAB = 0,
+ TS_LAST_WAS_TAB,
+ TS_LIST_WAS_PRINTED,
+ TS_MENU_MODE,
+};
+
+
/* Do TAB completion */
-static NOINLINE void input_tab(smallint *lastWasTab)
+static NOINLINE void input_tab(smallint *lastWasTab, smallint is_meta)
{
char *chosen_match;
char *match_buf;
size_t len_found;
/* Length of string used for matching */
unsigned match_pfx_len = match_pfx_len;
+#if !ENABLE_FEATURE_EDITING_EXT
+#define cur_remlen 0
+#else
+#define cmpmenu_org_pfx (S.cmpmenu_org_pfx)
+#define cmpmenu_curlen (S.cmpmenu_curlen)
+#define cmpmenu_curpos (S.cmpmenu_curpos)
+ int cur_remlen = 0;
+# endif
int find_type;
# if ENABLE_UNICODE_SUPPORT
/* cursor pos in command converted to multibyte form */
int cursor_mb;
# endif
+
+ auto void save_cmdline_prefix_in_matchbuf(void);
+ void save_cmdline_prefix_in_matchbuf(void)
+ {
+ /* Make a local copy of the string up to the position of the cursor.
+ * build_match_prefix will expand it into int16_t's, need to allocate
+ * twice as much as the string_len+1.
+ * (we then also (ab)use this extra space later - see (**))
+ */
+ match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
+# if !ENABLE_UNICODE_SUPPORT
+ save_string(match_buf, cursor + 1); /* +1 for NUL */
+# else
+ {
+ CHAR_T wc = command_ps[cursor];
+ command_ps[cursor] = BB_NUL;
+ save_string(match_buf, MAX_LINELEN);
+ command_ps[cursor] = wc;
+ cursor_mb = strlen(match_buf);
+ }
+# endif
+ }
+
if (!(state->flags & TAB_COMPLETION))
return;
@@ -1085,36 +1138,65 @@
/* The last char was a TAB too.
* Print a list of all the available choices.
*/
+#if ENABLE_FEATURE_EDITING_EXT
+ if (num_matches > 1 && ((is_meta && *lastWasTab > TS_LAST_WAS_TAB) ||
+ *lastWasTab > TS_LIST_WAS_PRINTED)) {
+ int wholeword = 1;
+ *lastWasTab = TS_MENU_MODE;
+ cur_remlen = cmpmenu_curlen;
+ save_cmdline_prefix_in_matchbuf(); /* setup match_buf & cursor_mb */
+#if ENABLE_UNICODE_SUPPORT
+ cursor_mb -= cmpmenu_curlen;
+#else
+ cursor -= cmpmenu_curlen;
+# endif
+
+ if (is_meta && cmpmenu_curpos < num_matches) { /* Forward one match */
+ chosen_match = quote_special_chars(matches[++cmpmenu_curpos - 1]);
+ } else if (!is_meta && cmpmenu_curpos > 1) { /* Backward one match */
+ chosen_match = quote_special_chars(matches[--cmpmenu_curpos - 1]);
+ } else { /* Back to start */
+ beep();
+ wholeword = 0;
+ cmpmenu_curpos = is_meta ? 0 : (num_matches + 1);
+ chosen_match = quote_special_chars(matches[0]);
+ chosen_match[cmpmenu_org_pfx] = 0;
+ }
+ match_pfx_len = 0;
+ len_found = strlen(chosen_match);
+ if (wholeword && chosen_match[len_found-1] != '/') {
+ chosen_match[len_found] = ' ';
+ chosen_match[++len_found] = '\0';
+ }
+ cmpmenu_curlen = len_found;
+#if 0
+ printf("\nLW:%d CR:%d CL:%d ORG:%d CRS:%d M'%s'\n",
+ *lastWasTab, cur_remlen, cmpmenu_curlen,
+ cmpmenu_org_pfx, cursor, chosen_match);
+#endif
+ goto do_redraw;
+ } else
+#endif
if (num_matches > 0) {
/* cursor will be changed by goto_new_line() */
int sav_cursor = cursor;
+ *lastWasTab = TS_LIST_WAS_PRINTED;
goto_new_line();
showfiles();
redraw(0, command_len - sav_cursor);
}
return;
}
+#if ENABLE_FEATURE_EDITING_EXT
+ cmpmenu_org_pfx = 0; /* reset */
+ cmpmenu_curlen = 0;
+ cmpmenu_curpos = 0;
+#endif
- *lastWasTab = 1;
+ *lastWasTab = TS_LAST_WAS_TAB;
chosen_match = NULL;
- /* Make a local copy of the string up to the position of the cursor.
- * build_match_prefix will expand it into int16_t's, need to allocate
- * twice as much as the string_len+1.
- * (we then also (ab)use this extra space later - see (**))
- */
- match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
-# if !ENABLE_UNICODE_SUPPORT
- save_string(match_buf, cursor + 1); /* +1 for NUL */
-# else
- {
- CHAR_T wc = command_ps[cursor];
- command_ps[cursor] = BB_NUL;
- save_string(match_buf, MAX_LINELEN);
- command_ps[cursor] = wc;
- cursor_mb = strlen(match_buf);
- }
-# endif
+ save_cmdline_prefix_in_matchbuf();
find_type = build_match_prefix(match_buf);
/* Free up any memory already allocated */
@@ -1197,6 +1279,11 @@
}
}
+#if ENABLE_FEATURE_EDITING_EXT
+ cmpmenu_org_pfx = len_found;
+ cmpmenu_curlen = len_found;
+#endif
+do_redraw:
# if !ENABLE_UNICODE_SUPPORT
/* Have space to place the match? */
/* The result consists of three parts with these lengths: */
@@ -1205,7 +1292,7 @@
if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) {
int pos;
/* save tail */
- strcpy(match_buf, &command_ps[cursor]);
+ strcpy(match_buf, &command_ps[cursor + cur_remlen]);
/* add match and tail */
sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
command_len = strlen(command_ps);
@@ -1224,7 +1311,7 @@
if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) {
int pos;
/* save tail */
- strcpy(match_buf, &command[cursor_mb]);
+ strcpy(match_buf, &command[cursor_mb + cur_remlen]);
/* where do we want to have cursor after all? */
strcpy(&command[cursor_mb], chosen_match + match_pfx_len);
len = load_string(command);
@@ -1943,6 +2030,36 @@
# define isrtl_str() 0
#endif
+static void insert_text(const CHAR_T *c, int n)
+{
+ while (n--) {
+ CHAR_T ic = *c++;
+
+ command_len++;
+ if (cursor == (command_len - 1)) {
+ /* We are at the end, append */
+ command_ps[cursor] = ic;
+ command_ps[cursor + 1] = BB_NUL;
+ put_cur_glyph_and_inc_cursor();
+ if (unicode_bidi_isrtl(ic))
+ input_backward(1);
+ } else {
+ /* In the middle, insert */
+ int sc = cursor;
+
+ memmove(command_ps + sc + 1, command_ps + sc,
+ (command_len - sc) * sizeof(command_ps[0]));
+ command_ps[sc] = ic;
+ /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
+ if (!isrtl_str())
+ sc++; /* no */
+ put_till_end_and_adv_cursor();
+ /* to prev x pos + 1 */
+ input_backward(cursor - sc);
+ }
+ }
+}
+
/* leave out the "vi-mode"-only case labels if vi editing isn't
* configured. */
#define vi_case(caselabel) IF_FEATURE_EDITING_VI(case caselabel)
@@ -1950,6 +2067,7 @@
/* convert uppercase ascii to equivalent control char, for readability */
#undef CTRL
#define CTRL(a) ((a) & ~0x40)
+#define META(a) ((a) | 0x80)
enum {
VI_CMDMODE_BIT = 0x40000000,
@@ -2101,6 +2219,10 @@
#if ENABLE_FEATURE_EDITING_VI
smallint vi_cmdmode = 0;
#endif
+#if ENABLE_FEATURE_EDITING_EXT && MAX_HISTORY > 0
+ int search_prefix = 0;
+ int yank_end = 0;
+#endif
struct termios initial_settings;
struct termios new_settings;
char read_key_buffer[KEYCODE_BUFFER_SIZE];
@@ -2133,8 +2255,10 @@
#if MAX_HISTORY > 0
# if ENABLE_FEATURE_EDITING_SAVEHISTORY
if ((state->flags & SAVE_HISTORY) && state->hist_file)
- if (state->cnt_history == 0)
+ if (state->cnt_history == 0) {
load_history(state);
+ state->cur_cmdno = state->cnt_history;
+ }
# endif
if (state->flags & DO_HISTORY)
state->cur_history = state->cnt_history;
@@ -2261,7 +2385,7 @@
break;
#if ENABLE_FEATURE_TAB_COMPLETION
case '\t':
- input_tab(&lastWasTab);
+ input_tab(&lastWasTab, FALSE);
break;
#endif
case CTRL('K'):
@@ -2274,6 +2398,10 @@
vi_case(CTRL('L')|VI_CMDMODE_BIT:)
/* Control-l -- clear screen */
printf(ESC"[H"); /* cursor to top,left */
+#if !ENABLE_FEATURE_REVERSE_SEARCH
+ case CTRL('R'):
+#endif
+ case CTRL('X'): /* Redraw line */
redraw(0, command_len - cursor);
break;
#if MAX_HISTORY > 0
@@ -2446,14 +2574,186 @@
bb_putchar('\b');
}
break;
+#endif /* FEATURE_COMMAND_EDITING_VI */
+#if ENABLE_FEATURE_EDITING_EXT
+ case KEYCODE_SHIFT_TAB:
+ case KEYCODE_ALT_UP:
+ case KEYCODE_ALT_DOWN:
+ case KEYCODE_ALT_LEFT:
+ case KEYCODE_ALT_RIGHT:
+ case KEYCODE_ALT_DELETE:
+ // Continue into ESC handling
+#endif
case '\x1b': /* ESC */
+#if ENABLE_FEATURE_EDITING_VI
if (state->flags & VI_MODE) {
/* insert mode --> command mode */
- vi_cmdmode = 1;
- input_backward(1);
+ if (ic == '\x1b') {
+ vi_cmdmode = 1;
+ input_backward(1);
+ }
+ break;
+ }
+#endif
+#if ENABLE_FEATURE_EDITING_EXT
+ {
+ int i2 = ic == '\x1b' ? read_key(STDIN_FILENO, read_key_buffer, timeout) : ic;
+
+ switch (i2) {
+ case KEYCODE_ALT_LEFT:
+ case KEYCODE_LEFT:
+ case 'b':
+ ctrl_left();
+ break;
+ case KEYCODE_ALT_RIGHT:
+ case KEYCODE_RIGHT:
+ case 'f':
+ ctrl_right();
+ break;
+ case KEYCODE_ALT_DELETE:
+ case KEYCODE_DELETE:
+ case 'd': {
+ /* M-d Delete word forward */
+ int nc, sc = cursor;
+ ctrl_right();
+ nc = cursor;
+ input_backward(cursor - sc);
+ while (nc >= 0 && nc-- >= cursor)
+ input_delete(1);
+ break;
+ }
+ case '\b': /* ^H */
+ case '\x7f': /* DEL */
+ case 'w': {
+ /* M-w Delete word backward */
+ int sc = cursor;
+ ctrl_left();
+ while (sc-- > cursor)
+ input_delete(1);
+ break;
+ }
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ case KEYCODE_SHIFT_TAB:
+ case '\t':
+ input_tab(&lastWasTab, TRUE);
+ break;
+#endif
+#if MAX_HISTORY > 0
+ case KEYCODE_ALT_UP:
+ case KEYCODE_UP:
+ case 'p':
+ case KEYCODE_ALT_DOWN:
+ case KEYCODE_DOWN:
+ case 'n':
+ {
+ int is_up = 0;
+ switch (i2) {
+ case KEYCODE_ALT_UP:
+ case KEYCODE_UP:
+ case 'p':
+ is_up = 1;
+ }
+ /* Meta-n -- Search next command from history */
+ search_prefix = cursor;
+ if (state->flags & DO_HISTORY) {
+ int ch = state->cur_history + (is_up ? -1 : 1);
+# if ENABLE_UNICODE_SUPPORT
+ char cmdpfx[MAX_LINELEN];
+ CHAR_T sc = command_ps[search_prefix];
+ int pfxlen;
+ command_ps[search_prefix] = BB_NUL;
+ pfxlen = save_string(cmdpfx, sizeof(cmdpfx));
+ command_ps[search_prefix] = sc;
+#else
+ int pfxlen = search_prefix;
+ char *cmdpfx = command_ps;
+#endif
+ while ((!is_up && ch < state->cnt_history) ||
+ (is_up && ch >= 0)) {
+ if (state->history[ch] && 0 == strncmp(cmdpfx, state->history[ch], pfxlen)) {
+ state->cur_history = ch;
+ goto rewrite_line;
+ }
+ ch += is_up ? -1 : 1;
+ }
+ }
+ if (!is_up && cursor < command_len) {
+ command_ps[cursor] = BB_NUL;
+ command_len = cursor;
+ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
+ state->cur_history = state->cnt_history;
+ }
+ beep();
+ break;
+ }
+ case '.':
+ case '_':
+ // Insert last word from previous command. More previous on repeat
+ if (yank_end == 0) {
+ yank_end = state->cnt_history;
+ search_prefix = cursor;
+ }
+ if ((state->flags & DO_HISTORY) && yank_end > 0) {
+ char *cmd;
+ int ix;
+ int cursor_middle;
+ smallint in_sq = 0, in_dq = 0;
+
+ while (cursor > search_prefix)
+ input_backspace();
+
+ cmd = state->history[--yank_end];
+ if (!cmd)
+ break;
+
+ /* Find last shell token in line (approximately) */
+ for (ix = strlen(cmd) - 1; ix > 0; ix--) {
+ if (cmd[ix] == '"' || cmd[ix] == '`') {
+ if (in_dq == cmd[ix] && (ix == 0 || cmd[ix-1] != '\\'))
+ in_dq = 0;
+ else if (!in_sq && !in_dq)
+ in_dq = cmd[ix];
+ }
+ else if (cmd[ix] == '\'' && !in_dq)
+ in_sq = in_sq ? 0 : 1;
+ if (!in_dq && !in_sq &&
+ strchr(" \t<>;&|", cmd[ix-1]) && (ix < 2 || cmd[ix-2] != '\\'))
+ break;
+ }
+ if ((int)command_len > maxsize - strlen(cmd + ix) - 2)
+ break;
+// printf("\nYE:%d:%d SP:%d IX:%d'%s'\n", yank_end, state->cnt_history, search_prefix, ix, cmd + ix);
+
+#if ENABLE_UNICODE_SUPPORT
+ {
+ int siz = strlen(cmd + ix);
+ CHAR_T *word = xzalloc((siz + 1) * sizeof(command_ps[0]));
+ ssize_t wlen = mbstowcs(word, cmd + ix, (siz + 1) * sizeof(command_ps[0]));
+ cursor_middle = cursor + wlen;
+ if (cursor == command_len - 1) {
+ CHAR_T spc = ' ';
+ insert_text(&spc, 1);
+ cursor_middle = 0;
+ }
+ insert_text(word, wlen);
+ free(word);
+ }
+#else
+ cursor_middle = cursor + strlen(cmd + ix);
+ if (cursor == command_len - 1) {
+ insert_text(" ", 1);
+ cursor_middle = 0;
+ }
+ insert_text(cmd + ix, strlen(cmd + ix));
+#endif
+ }
+ break;
+#endif
+ }
}
+#endif
break;
-#endif /* FEATURE_COMMAND_EDITING_VI */
#if MAX_HISTORY > 0
case KEYCODE_UP:
@@ -2470,6 +2770,11 @@
command_len = load_string(state->history[state->cur_history] ?
state->history[state->cur_history] : "");
/* redraw and go to eol (bol, in vi) */
+#if ENABLE_FEATURE_EDITING_EXT
+ if (search_prefix > 0)
+ redraw(cmdedit_y, command_len - search_prefix);
+ else
+#endif
redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
break;
#endif
@@ -2544,27 +2849,13 @@
break;
}
- command_len++;
- if (cursor == (command_len - 1)) {
- /* We are at the end, append */
- command_ps[cursor] = ic;
- command_ps[cursor + 1] = BB_NUL;
- put_cur_glyph_and_inc_cursor();
- if (unicode_bidi_isrtl(ic))
- input_backward(1);
- } else {
- /* In the middle, insert */
- int sc = cursor;
-
- memmove(command_ps + sc + 1, command_ps + sc,
- (command_len - sc) * sizeof(command_ps[0]));
- command_ps[sc] = ic;
- /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
- if (!isrtl_str())
- sc++; /* no */
- put_till_end_and_adv_cursor();
- /* to prev x pos + 1 */
- input_backward(cursor - sc);
+#if ENABLE_FEATURE_EDITING_EXT
+ search_prefix = 0;
+ yank_end = 0;
+#endif
+ {
+ CHAR_T ics[1] = { ic };
+ insert_text(ics, 1);
}
break;
} /* switch (ic) */
@@ -2573,7 +2864,7 @@
break;
#if ENABLE_FEATURE_TAB_COMPLETION
- if (ic_raw != '\t')
+ if (ic_raw != '\t' && ic_raw != KEYCODE_SHIFT_TAB)
lastWasTab = 0;
#endif
} /* while (1) */
@@ -2603,8 +2894,10 @@
free(command_ps);
#endif
- if (command_len > 0)
+ if (command_len > 0) {
remember_in_history(command);
+ state->cur_cmdno++;
+ }
if (break_out > 0) {
command[command_len++] = '\n';
@@ -2627,6 +2920,57 @@
return len; /* can't return command_len, DEINIT_S() destroys it */
}
+void FAST_FUNC line_input_help(void)
+{
+#if ENABLE_FEATURE_EDITING_HELP
+ printf("Line editing:\n-------------------\n%s\n",
+ "\t" "C-A, <Home> Move to start of line\n"
+ "\t" "C-E, <End> Move to end of line\n"
+ "\t" "C-B, <Left> Move back one char\n"
+ "\t" "C-F, <Right> Move forward one char\n"
+#if !ENABLE_FEATURE_EDITING_EXT
+ "\t" "C-Left Move word backward\n"
+ "\t" "C-Right Move word forward\n"
+#endif
+ "\t" "C-D Delete one char or exit\n"
+ "\t" "<Del> Delete one char to the right\n"
+ "\t" "C-H Delete one char to the left\n"
+ "\t" "C-W Delete one Word to the left\n"
+ "\t" "C-U Clear line before cursor\n"
+ "\t" "C-K Kill / Clear rest of line\n"
+ "\t" "C-L Clear screen\n"
+#if ENABLE_FEATURE_REVERSE_SEARCH && MAX_HISTORY > 0
+ "\t" "C-R Inremental reverse history search\n"
+ "\t" "C-X Redraw line\n"
+#else
+ "\t" "C-R C-X Redraw line\n"
+#endif
+#if MAX_HISTORY > 0
+ "\t" "C-P, <Up> Get previous command line\n"
+ "\t" "C-N, <Down> Get next command line\n"
+#endif
+#if ENABLE_FEATURE_TAB_COMPLETION
+ "\t" "<Tab> Tab completion\n"
+#endif
+#if ENABLE_FEATURE_EDITING_EXT
+#if ENABLE_FEATURE_TAB_COMPLETION
+ "\t" "M-Tab, S-Tab Tab menu forward. <Tab> goes back again\n"
+#endif
+ "\t" "M-b, C-Left Move word backward\n"
+ "\t" "M-f, C-Right Move word forward\n"
+ "\t" "M-w, M-BkSpace Delete word backward\n"
+ "\t" "M-d, M-Delete Delete word forward\n"
+#if MAX_HISTORY > 0
+ "\t" "M-P, M-Up Get previous line, matching prefix\n"
+ "\t" "M-N, M-Down Get next line, matching prefix\n"
+ "\t" "M-., M-_ Insert last word of previous line\n"
+#endif
+#endif
+
+ );
+#endif
+}
+
#else /* !FEATURE_EDITING */
#undef read_line_input
--- busybox-1.19.0/libbb/read_key.c.orig
+++ busybox-1.19.0/libbb/read_key.c
@@ -47,6 +47,7 @@
'[','H' |0x80,KEYCODE_HOME , /* xterm */
/* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
'[','F' |0x80,KEYCODE_END , /* xterm */
+ '[','Z' |0x80,KEYCODE_SHIFT_TAB,
'[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
'[','2','~' |0x80,KEYCODE_INSERT ,
/* ESC [ 2 ; 3 ~ - Alt-Insert */
@@ -86,6 +87,11 @@
/* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
'[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
'[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
+ '[','1',';','3','A' |0x80,KEYCODE_ALT_UP,
+ '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN ,
+ '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT,
+ '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT ,
+ '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE ,
0
/* ESC [ Z - Shift-Tab */
};
--- busybox-1.19.0/miscutils/inotifyd.c.orig
+++ busybox-1.19.0/miscutils/inotifyd.c
@@ -101,6 +101,7 @@
args[0] = *argv;
args[4] = NULL;
argc -= 2; // number of files we watch
+ int echo = strcmp(*argv, "echo") == 0;
// open inotify
pfd.fd = inotify_init();
@@ -177,12 +178,17 @@
*s++ = mask_names[i];
}
*s = '\0';
-// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0],
-// ie->mask, events, watches[ie->wd], ie->len ? ie->name : "");
- args[1] = events;
- args[2] = watches[ie->wd];
- args[3] = ie->len ? ie->name : NULL;
- spawn_and_wait((char **)args);
+ if (echo) {
+ printf("%s\t%s\t%s\n", events, watches[ie->wd], ie->len ? ie->name : "");
+ }
+ else {
+// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0],
+// ie->mask, events, watches[ie->wd], ie->len ? ie->name : "");
+ args[1] = events;
+ args[2] = watches[ie->wd];
+ args[3] = ie->len ? ie->name : NULL;
+ spawn_and_wait((char **)args);
+ }
// we are done if all files got final x event
if (ie->mask & 0x8000) {
if (--argc <= 0)
--- busybox-1.19.0/procps/Config.src.orig
+++ busybox-1.19.0/procps/Config.src
@@ -96,6 +96,14 @@
If given once, 132 chars are printed, and if given more
than once, the length is unlimited.
+config FEATURE_PS_LONG
+ bool "Enable long output option (-l)"
+ default y
+ depends on PS
+ help
+ Support argument 'l' for long output.
+ Adds fields PPID, RSS, START, TIME & TTY
+
config FEATURE_PS_TIME
bool "Enable time and elapsed time output"
default y
--- busybox-1.19.0/procps/ps.c.orig
+++ busybox-1.19.0/procps/ps.c
@@ -39,6 +39,12 @@
//usage: IF_FEATURE_PS_WIDE(
//usage: "\n w Wide output"
//usage: )
+//usage: IF_FEATURE_PS_LONG(
+//usage: "\n l Long output"
+//usage: )
+//usage: IF_FEATURE_SHOW_THREADS(
+//usage: "\n T Show threads"
+//usage: )
//usage:
//usage:#endif /* ENABLE_DESKTOP */
//usage:
@@ -56,15 +62,15 @@
//usage: " 2990 andersen andersen R ps\n"
#include "libbb.h"
+#ifdef __linux__
+# include <sys/sysinfo.h>
+#endif
/* Absolute maximum on output line length */
enum { MAX_WIDTH = 2*1024 };
#if ENABLE_DESKTOP
-#ifdef __linux__
-# include <sys/sysinfo.h>
-#endif
#include <sys/times.h> /* for times() */
#ifndef AT_CLKTCK
# define AT_CLKTCK 17
@@ -625,15 +631,17 @@
enum {
OPT_Z = (1 << 0) * ENABLE_SELINUX,
OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS,
+ OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG,
};
int opts = 0;
/* If we support any options, parse argv */
-#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE
+#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG
# if ENABLE_FEATURE_PS_WIDE
/* -w is a bit complicated */
int w_count = 0;
opt_complementary = "-:ww";
- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count);
+ opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")
+ "w", &w_count);
/* if w is given once, GNU ps sets the width to 132,
* if w is given more than once, it is "unlimited"
*/
@@ -648,60 +656,95 @@
# else
/* -w is not supported, only -Z and/or -T */
opt_complementary = "-";
- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T"));
+ opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l"));
# endif
-#endif
#if ENABLE_SELINUX
- if ((opts & OPT_Z) && is_selinux_enabled()) {
- psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT
- | PSSCAN_STATE | PSSCAN_COMM;
- puts(" PID CONTEXT STAT COMMAND");
- } else
+ if ((opts & OPT_Z) && is_selinux_enabled()) {
+ psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT
+ | PSSCAN_STATE | PSSCAN_COMM;
+ puts(" PID CONTEXT STAT COMMAND");
+ } else
+#endif
+ {
+ if (opts & OPT_T) {
+ psscan_flags |= PSSCAN_TASKS;
+ }
+ if (opts & OPT_l) {
+ psscan_flags |= PSSCAN_PPID | PSSCAN_RSS | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_TTY;
+ puts(" PID PPID USER VSZ RSS STAT START TIME TTY COMMAND");
+ }
+ else {
+ puts(" PID USER VSZ STAT COMMAND");
+ }
+ }
#endif
- {
- puts(" PID USER VSZ STAT COMMAND");
- }
- if (opts & OPT_T) {
- psscan_flags |= PSSCAN_TASKS;
- }
- p = NULL;
- while ((p = procps_scan(p, psscan_flags)) != NULL) {
- int len;
+ p = NULL;
+ while ((p = procps_scan(p, psscan_flags)) != NULL) {
+ int len;
#if ENABLE_SELINUX
- if (psscan_flags & PSSCAN_CONTEXT) {
- len = printf("%5u %-32.32s %s ",
- p->pid,
- p->context ? p->context : "unknown",
- p->state);
- } else
+ if (psscan_flags & PSSCAN_CONTEXT) {
+ len = printf("%5u %-32.32s %s ",
+ p->pid,
+ p->context ? p->context : "unknown",
+ p->state);
+ } else
#endif
- {
- const char *user = get_cached_username(p->uid);
- //if (p->vsz == 0)
- // len = printf("%5u %-8.8s %s ",
- // p->pid, user, p->state);
- //else
{
- char buf6[6];
- smart_ulltoa5(p->vsz, buf6, " mgtpezy");
- buf6[5] = '\0';
- len = printf("%5u %-8.8s %s %s ",
- p->pid, user, buf6, p->state);
+ const char *user = get_cached_username(p->uid);
+ //if (p->vsz == 0)
+ // len = printf("%5u %-8.8s %s ",
+ // p->pid, user, p->state);
+ //else
+ {
+ char buf6[6];
+ smart_ulltoa5(p->vsz, buf6, " mgtpezy");
+ buf6[5] = '\0';
+#if ENABLE_FEATURE_PS_LONG
+ if (opts & OPT_l) {
+ char bufr[6], strt[6], tty[20];
+ struct tm *tm;
+ int sut = (p->stime + p->utime) / 100;
+ time_t now = time(NULL);
+ struct sysinfo info;
+ int elap;
+
+ sysinfo(&info);
+ elap = info.uptime - (p->start_time / 100);
+ now -= elap;
+ tm = localtime((time_t *) &now);
+
+ smart_ulltoa5(p->vsz, buf6, "kmgtpezy");
+ smart_ulltoa5(p->rss, bufr, "kmgtpezy");
+ bufr[5] = '\0';
+ strcpy(tty, p->tty_major == 136 ? "pts" :
+ (p->tty_major == 4 || p->tty_major == 5) ? "tty" : "- ");
+ strcat(tty, p->tty_minor >= 64 ? "S" : "");
+ if (tty[2])
+ strcat(tty, itoa(p->tty_minor % 64));
+ strftime(strt, 6, (elap >= (24 * 3600)) ? "%b%d" : "%H:%M", tm);
+ strt[5] = '\0';
+ len = printf("%5u %5u %-4.4s %5s %5s %s %s %2d:%02d:%02d %5s ",
+ p->pid, p->ppid, user, buf6, bufr, p->state, strt,
+ sut / 3600, (sut % 3600) / 60, sut % 60, tty);
+ } else
+#endif
+ len = printf("%5u %-8.8s %s %s ",
+ p->pid, user, buf6, p->state);
+ }
}
- }
- {
- int sz = terminal_width - len;
- char buf[sz + 1];
- read_cmdline(buf, sz, p->pid, p->comm);
- puts(buf);
+ {
+ int sz = terminal_width - len;
+ char buf[sz + 1];
+ read_cmdline(buf, sz, p->pid, p->comm);
+ puts(buf);
+ }
}
+ if (ENABLE_FEATURE_CLEAN_UP)
+ clear_username_cache();
+ return EXIT_SUCCESS;
}
- if (ENABLE_FEATURE_CLEAN_UP)
- clear_username_cache();
- return EXIT_SUCCESS;
-}
#endif /* !ENABLE_DESKTOP */
--- busybox-1.19.0/shell/ash.c.orig
+++ busybox-1.19.0/shell/ash.c
@@ -8765,8 +8765,11 @@
if (!did_banner) {
/* note: ash and hush share this string */
out1fmt("\n\n%s %s\n"
- "Enter 'help' for a list of built-in commands."
- "\n\n",
+ "Enter 'help' for a list of built-in commands"
+#if ENABLE_FEATURE_EDITING_HELP
+ " and command line editing keys"
+#endif
+ ".\n\n",
bb_banner,
"built-in shell (ash)"
);
@@ -9019,6 +9022,9 @@
#if !ENABLE_FEATURE_SH_EXTRA_QUIET
static int helpcmd(int, char **) FAST_FUNC;
#endif
+#if MAX_HISTORY
+static int historycmd(int, char **) FAST_FUNC;
+#endif
#if ENABLE_SH_MATH_SUPPORT
static int letcmd(int, char **) FAST_FUNC;
#endif
@@ -9092,6 +9098,9 @@
#if !ENABLE_FEATURE_SH_EXTRA_QUIET
{ BUILTIN_NOSPEC "help" , helpcmd },
#endif
+#if MAX_HISTORY
+ { BUILTIN_NOSPEC "history", historycmd },
+#endif
#if JOBS
{ BUILTIN_REGULAR "jobs" , jobscmd },
{ BUILTIN_REGULAR "kill" , killcmd },
@@ -9163,6 +9172,27 @@
return bp;
}
+# if ENABLE_FEATURE_TAB_COMPLETION
+/*
+ * Add these as completion candidates
+ */
+static void add_aliases_and_builtins(void (*add)(const char *), void* arg UNUSED_PARAM)
+{
+ int i;
+ struct alias *ap;
+
+ for (i = 0; i < ATABSIZE; i++) {
+ for (ap = atab[i]; ap; ap = ap->next) {
+ add(ap->name);
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(builtintab); i++) {
+ add(builtintab[i].name + 1);
+ }
+}
+#endif
+
+
/*
* Execute a simple command.
*/
@@ -9632,6 +9662,7 @@
# endif
# if ENABLE_FEATURE_TAB_COMPLETION
line_input_state->path_lookup = pathval();
+ line_input_state->extra_cmd = add_aliases_and_builtins;
# endif
/* Unicode support should be activated even if LANG is set
* _during_ shell execution, not only if it was set when
@@ -12596,10 +12627,34 @@
}
#endif
out1fmt("\n\n");
+
+#if ENABLE_FEATURE_EDITING_HELP
+ line_input_help();
+#endif
return EXIT_SUCCESS;
}
#endif /* FEATURE_SH_EXTRA_QUIET */
+#if MAX_HISTORY
+/*
+ * Lists command history
+ */
+static int FAST_FUNC
+historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+ int i;
+ int n;
+
+ if (!line_input_state)
+ return EXIT_FAILURE;
+
+ n = line_input_state->cur_cmdno - line_input_state->cnt_history;
+ for (i = 0; i < line_input_state->cnt_history; i++, n++)
+ out1fmt("%4d %s\n", n, line_input_state->history[i]);
+ return EXIT_SUCCESS;
+}
+#endif
+
/*
* The export and readonly commands.
*/
--- busybox-1.19.0/shell/hush.c.orig
+++ busybox-1.19.0/shell/hush.c
@@ -83,7 +83,7 @@
*/
#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__APPLE__) \
- )
+ )
# include <malloc.h> /* for malloc_trim */
#endif
#include <glob.h>
@@ -853,6 +853,9 @@
#if ENABLE_HUSH_HELP
static int builtin_help(char **argv) FAST_FUNC;
#endif
+#if MAX_HISTORY
+static int builtin_history(char **argv) FAST_FUNC;
+#endif
#if ENABLE_HUSH_LOCAL
static int builtin_local(char **argv) FAST_FUNC;
#endif
@@ -922,6 +925,9 @@
#if ENABLE_HUSH_HELP
BLTIN("help" , builtin_help , NULL),
#endif
+#if MAX_HISTORY
+ BLTIN("history" , builtin_history , NULL),
+#endif
#if ENABLE_HUSH_JOB
BLTIN("jobs" , builtin_jobs , "List jobs"),
#endif
@@ -1292,6 +1298,21 @@
G.global_args_malloced = sv->sv_g_malloced;
}
+# if ENABLE_FEATURE_TAB_COMPLETION
+/*
+ * Add these as completion candidates
+ */
+static void add_aliases_and_builtins(void (*add)(const char *), void* arg UNUSED_PARAM)
+{
+ /* TODO: Add aliases support (along with aliases per se) */
+ const struct built_in_command *x;
+ for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) {
+ add(x->b_cmd);
+ }
+}
+#endif
+
+
/* Basic theory of signal handling in shell
* ========================================
@@ -2547,7 +2568,7 @@
return o_save_ptr_helper(o, n);
}
if (gr == GLOB_NOSPACE)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
* but we didn't specify it. Paranoia again. */
bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -7831,6 +7852,9 @@
hp = get_local_var_value("HISTFILESIZE");
G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
# endif
+# if ENABLE_FEATURE_TAB_COMPLETION
+ G.line_input_state->extra_cmd = add_aliases_and_builtins;
+# endif
}
# endif
#endif
@@ -8135,8 +8159,11 @@
if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) {
/* note: ash and hush share this string */
printf("\n\n%s %s\n"
- IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n")
- "\n",
+ IF_HUSH_HELP("Enter 'help' for a list of built-in commands")
+#if ENABLE_FEATURE_EDITING_HELP
+ " and command line editing keys"
+#endif
+ ".\n\n",
bb_banner,
"hush - the humble shell"
);
@@ -8621,10 +8648,32 @@
printf("%-10s%s\n", x->b_cmd, x->b_descr);
}
bb_putchar('\n');
+#if ENABLE_FEATURE_EDITING_HELP
+ line_input_help();
+#endif
return EXIT_SUCCESS;
}
#endif
+#if MAX_HISTORY
+/*
+ * Lists command history
+ */
+static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
+{
+ int i;
+ int n;
+
+ if (!G.line_input_state)
+ return EXIT_FAILURE;
+
+ n = G.line_input_state->cur_cmdno - G.line_input_state->cnt_history;
+ for (i = 0; i < G.line_input_state->cnt_history; i++, n++)
+ printf("%4d %s\n", n, G.line_input_state->history[i]);
+ return EXIT_SUCCESS;
+}
+#endif
+
#if ENABLE_HUSH_JOB
static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
{
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox