[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: PATCH: line_edit, ps, inotify features
From: Flemming Madsen <busybox () themadsens ! dk>
Date: 2011-08-31 18:19:51
Message-ID: CACWu54X01YYnGPrW2Sg7gRAqKoqeaULw6DnVDcLWc0EYTv62BQ () mail ! gmail ! com
[Download RAW message or body]
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
["flemming.patch" (text/x-patch)]
--- 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)(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,22 @@
const char *pfind;
char *dirbuf = NULL;
+ void add_match_if(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 +1078,57 @@
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
+
+ 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 +1136,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;
+#if ENABLE_UNICODE_SUPPORT
+ save_cmdline_prefix_in_matchbuf(); /* make sure to set cursor_mb */
+ 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 +1277,11 @@
}
}
+#if ENABLE_FEATURE_EDITING_EXT
+ cmpmenu_org_pfx = match_pfx_len;
+ cmpmenu_curlen = match_pfx_len;
+#endif
+do_redraw:
# if !ENABLE_UNICODE_SUPPORT
/* Have space to place the match? */
/* The result consists of three parts with these lengths: */
@@ -1205,7 +1290,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 +1309,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 +2028,36 @@
# define isrtl_str() 0
#endif
+static void insert_text(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 +2065,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 +2217,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 +2253,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 +2383,7 @@
break;
#if ENABLE_FEATURE_TAB_COMPLETION
case '\t':
- input_tab(&lastWasTab);
+ input_tab(&lastWasTab, FALSE);
break;
#endif
case CTRL('K'):
@@ -2274,6 +2396,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 +2572,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;
+ ic_raw = 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 '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 (ic) {
+ 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 +2768,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 +2847,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 +2862,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 +2892,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 +2918,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
-#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;
+ 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
+
+ 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
-#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);
- }
- }
-
- {
- 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 (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';
+#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);
+ }
+ }
+ 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)(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 mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic