Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/libbb/lineedit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1179 - (hide annotations) (download)
Wed Dec 15 21:33:41 2010 UTC (13 years, 5 months ago) by niro
File MIME type: text/plain
File size: 61515 byte(s)
-updated to busybox-1.17.4
1 niro 816 /* vi: set sw=4 ts=4: */
2     /*
3     * Termios command line History and Editing.
4     *
5     * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
6     * Written by: Vladimir Oleynik <dzo@simtreas.ru>
7     *
8     * Used ideas:
9     * Adam Rogoyski <rogoyski@cs.utexas.edu>
10     * Dave Cinege <dcinege@psychosis.com>
11     * Jakub Jelinek (c) 1995
12     * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
13     *
14     * This code is 'as is' with no warranty.
15     */
16    
17     /*
18     * Usage and known bugs:
19 niro 984 * Terminal key codes are not extensive, more needs to be added.
20     * This version was created on Debian GNU/Linux 2.x.
21 niro 816 * Delete, Backspace, Home, End, and the arrow keys were tested
22     * to work in an Xterm and console. Ctrl-A also works as Home.
23     * Ctrl-E also works as End.
24     *
25 niro 984 * The following readline-like commands are not implemented:
26     * ESC-b -- Move back one word
27     * ESC-f -- Move forward one word
28     * ESC-d -- Delete forward one word
29     * CTL-t -- Transpose two characters
30     *
31 niro 816 * lineedit does not know that the terminal escape sequences do not
32     * take up space on the screen. The redisplay code assumes, unless
33     * told otherwise, that each character in the prompt is a printable
34     * character that takes up one character position on the screen.
35     * You need to tell lineedit that some sequences of characters
36     * in the prompt take up no screen space. Compatibly with readline,
37     * use the \[ escape to begin a sequence of non-printing characters,
38     * and the \] escape to signal the end of such a sequence. Example:
39     *
40     * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
41     */
42     #include "libbb.h"
43 niro 984 #include "unicode.h"
44 niro 816
45     #ifdef TEST
46 niro 984 # define ENABLE_FEATURE_EDITING 0
47     # define ENABLE_FEATURE_TAB_COMPLETION 0
48     # define ENABLE_FEATURE_USERNAME_COMPLETION 0
49     #endif
50 niro 816
51    
52     /* Entire file (except TESTing part) sits inside this #if */
53     #if ENABLE_FEATURE_EDITING
54    
55    
56     #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
57     (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
58 niro 984 #define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...)
59 niro 816 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
60 niro 984 #undef IF_FEATURE_GETUSERNAME_AND_HOMEDIR
61     #define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__
62 niro 816 #endif
63    
64 niro 984
65 niro 1123 #define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J"
66     //#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K"
67    
68    
69 niro 984 #undef CHAR_T
70 niro 1123 #if ENABLE_UNICODE_SUPPORT
71     # define BB_NUL ((wchar_t)0)
72 niro 984 # define CHAR_T wchar_t
73     static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
74     # if ENABLE_FEATURE_EDITING_VI
75     static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); }
76     # endif
77     static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
78     # undef isspace
79     # undef isalnum
80     # undef ispunct
81     # undef isprint
82     # define isspace isspace_must_not_be_used
83     # define isalnum isalnum_must_not_be_used
84     # define ispunct ispunct_must_not_be_used
85     # define isprint isprint_must_not_be_used
86     #else
87     # define BB_NUL '\0'
88     # define CHAR_T char
89     # define BB_isspace(c) isspace(c)
90     # define BB_isalnum(c) isalnum(c)
91     # define BB_ispunct(c) ispunct(c)
92     #endif
93    
94    
95 niro 1123 # if ENABLE_UNICODE_PRESERVE_BROKEN
96     # define unicode_mark_raw_byte(wc) ((wc) | 0x20000000)
97     # define unicode_is_raw_byte(wc) ((wc) & 0x20000000)
98     # else
99     # define unicode_is_raw_byte(wc) 0
100     # endif
101    
102    
103 niro 816 enum {
104     /* We use int16_t for positions, need to limit line len */
105     MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
106     ? CONFIG_FEATURE_EDITING_MAX_LEN
107     : 0x7ff0
108     };
109    
110     #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
111     static const char null_str[] ALIGN1 = "";
112     #endif
113    
114     /* We try to minimize both static and stack usage. */
115     struct lineedit_statics {
116     line_input_t *state;
117    
118     volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
119     sighandler_t previous_SIGWINCH_handler;
120    
121 niro 984 unsigned cmdedit_x; /* real x (col) terminal position */
122     unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
123 niro 816 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
124    
125     unsigned cursor;
126 niro 984 int command_len; /* must be signed */
127     /* signed maxsize: we want x in "if (x > S.maxsize)"
128     * to _not_ be promoted to unsigned */
129     int maxsize;
130     CHAR_T *command_ps;
131 niro 816
132     const char *cmdedit_prompt;
133     #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
134     int num_ok_lines; /* = 1; */
135     #endif
136    
137     #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
138     char *user_buf;
139     char *home_pwd_buf; /* = (char*)null_str; */
140     #endif
141    
142     #if ENABLE_FEATURE_TAB_COMPLETION
143     char **matches;
144     unsigned num_matches;
145     #endif
146    
147     #if ENABLE_FEATURE_EDITING_VI
148     #define DELBUFSIZ 128
149 niro 984 CHAR_T *delptr;
150 niro 816 smallint newdelflag; /* whether delbuf should be reused yet */
151 niro 984 CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
152 niro 816 #endif
153 niro 984 #if ENABLE_FEATURE_EDITING_ASK_TERMINAL
154     smallint sent_ESC_br6n;
155     #endif
156 niro 816
157     /* Formerly these were big buffers on stack: */
158     #if ENABLE_FEATURE_TAB_COMPLETION
159     char input_tab__matchBuf[MAX_LINELEN];
160     int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
161     int16_t find_match__pos_buf[MAX_LINELEN + 1];
162     #endif
163     };
164    
165     /* See lineedit_ptr_hack.c */
166     extern struct lineedit_statics *const lineedit_ptr_to_statics;
167    
168     #define S (*lineedit_ptr_to_statics)
169     #define state (S.state )
170     #define cmdedit_termw (S.cmdedit_termw )
171     #define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
172     #define cmdedit_x (S.cmdedit_x )
173     #define cmdedit_y (S.cmdedit_y )
174     #define cmdedit_prmt_len (S.cmdedit_prmt_len)
175     #define cursor (S.cursor )
176     #define command_len (S.command_len )
177     #define command_ps (S.command_ps )
178     #define cmdedit_prompt (S.cmdedit_prompt )
179     #define num_ok_lines (S.num_ok_lines )
180     #define user_buf (S.user_buf )
181     #define home_pwd_buf (S.home_pwd_buf )
182     #define matches (S.matches )
183     #define num_matches (S.num_matches )
184     #define delptr (S.delptr )
185     #define newdelflag (S.newdelflag )
186     #define delbuf (S.delbuf )
187    
188     #define INIT_S() do { \
189     (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
190     barrier(); \
191     cmdedit_termw = 80; \
192 niro 984 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
193     IF_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \
194 niro 816 } while (0)
195     static void deinit_S(void)
196     {
197     #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
198     /* This one is allocated only if FANCY_PROMPT is on
199     * (otherwise it points to verbatim prompt (NOT malloced) */
200     free((char*)cmdedit_prompt);
201     #endif
202     #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
203     free(user_buf);
204     if (home_pwd_buf != null_str)
205     free(home_pwd_buf);
206     #endif
207     free(lineedit_ptr_to_statics);
208     }
209     #define DEINIT_S() deinit_S()
210    
211    
212 niro 1123 #if ENABLE_UNICODE_SUPPORT
213 niro 984 static size_t load_string(const char *src, int maxsize)
214     {
215     ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
216     if (len < 0)
217     len = 0;
218 niro 1123 command_ps[len] = 0;
219 niro 984 return len;
220     }
221 niro 1123 static unsigned save_string(char *dst, unsigned maxsize)
222 niro 984 {
223 niro 1123 # if !ENABLE_UNICODE_PRESERVE_BROKEN
224 niro 984 ssize_t len = wcstombs(dst, command_ps, maxsize - 1);
225     if (len < 0)
226     len = 0;
227     dst[len] = '\0';
228     return len;
229 niro 1123 # else
230     unsigned dstpos = 0;
231     unsigned srcpos = 0;
232    
233     maxsize--;
234     while (dstpos < maxsize) {
235     wchar_t wc;
236     int n = srcpos;
237 niro 1179
238     /* Convert up to 1st invalid byte (or up to end) */
239 niro 1123 while ((wc = command_ps[srcpos]) != 0
240     && !unicode_is_raw_byte(wc)
241     ) {
242     srcpos++;
243     }
244     command_ps[srcpos] = 0;
245     n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
246     if (n < 0) /* should not happen */
247     break;
248     dstpos += n;
249     if (wc == 0) /* usually is */
250     break;
251 niro 1179
252 niro 1123 /* We do have invalid byte here! */
253     command_ps[srcpos] = wc; /* restore it */
254     srcpos++;
255     if (dstpos == maxsize)
256     break;
257     dst[dstpos++] = (char) wc;
258     }
259     dst[dstpos] = '\0';
260     return dstpos;
261     # endif
262 niro 984 }
263     /* I thought just fputwc(c, stdout) would work. But no... */
264     static void BB_PUTCHAR(wchar_t c)
265     {
266     char buf[MB_CUR_MAX + 1];
267     mbstate_t mbst = { 0 };
268 niro 1123 ssize_t len;
269 niro 984
270 niro 1123 len = wcrtomb(buf, c, &mbst);
271 niro 984 if (len > 0) {
272     buf[len] = '\0';
273     fputs(buf, stdout);
274     }
275     }
276 niro 1123 # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
277     static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc)
278     # else
279     static wchar_t adjust_width_and_validate_wc(wchar_t wc)
280     # define adjust_width_and_validate_wc(width_adj, wc) \
281     ((*(width_adj))++, adjust_width_and_validate_wc(wc))
282     # endif
283     {
284     int w = 1;
285    
286     if (unicode_status == UNICODE_ON) {
287     if (wc > CONFIG_LAST_SUPPORTED_WCHAR) {
288     /* note: also true for unicode_is_raw_byte(wc) */
289     goto subst;
290     }
291     w = wcwidth(wc);
292     if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0)
293     || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
294     || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
295     ) {
296     subst:
297     w = 1;
298     wc = CONFIG_SUBST_WCHAR;
299     }
300     }
301    
302     # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
303     *width_adj += w;
304     #endif
305     return wc;
306     }
307     #else /* !UNICODE */
308 niro 984 static size_t load_string(const char *src, int maxsize)
309     {
310     safe_strncpy(command_ps, src, maxsize);
311     return strlen(command_ps);
312     }
313     # if ENABLE_FEATURE_TAB_COMPLETION
314 niro 1123 static void save_string(char *dst, unsigned maxsize)
315 niro 984 {
316     safe_strncpy(dst, command_ps, maxsize);
317     }
318     # endif
319     # define BB_PUTCHAR(c) bb_putchar(c)
320 niro 1123 /* Should never be called: */
321     int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
322 niro 984 #endif
323    
324    
325 niro 816 /* Put 'command_ps[cursor]', cursor++.
326     * Advance cursor on screen. If we reached right margin, scroll text up
327     * and remove terminal margin effect by printing 'next_char' */
328     #define HACK_FOR_WRONG_WIDTH 1
329 niro 1123 static void put_cur_glyph_and_inc_cursor(void)
330 niro 816 {
331 niro 984 CHAR_T c = command_ps[cursor];
332 niro 1123 unsigned width = 0;
333     int ofs_to_right;
334 niro 816
335 niro 984 if (c == BB_NUL) {
336 niro 816 /* erase character after end of input string */
337     c = ' ';
338 niro 1123 } else {
339     /* advance cursor only if we aren't at the end yet */
340     cursor++;
341     if (unicode_status == UNICODE_ON) {
342     IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
343     c = adjust_width_and_validate_wc(&cmdedit_x, c);
344     IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
345     } else {
346     cmdedit_x++;
347     }
348 niro 816 }
349 niro 1123
350     ofs_to_right = cmdedit_x - cmdedit_termw;
351     if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
352     /* c fits on this line */
353 niro 984 BB_PUTCHAR(c);
354 niro 816 }
355 niro 1123
356     if (ofs_to_right >= 0) {
357     /* we go to the next line */
358 niro 816 #if HACK_FOR_WRONG_WIDTH
359     /* This works better if our idea of term width is wrong
360     * and it is actually wider (often happens on serial lines).
361     * Printing CR,LF *forces* cursor to next line.
362     * OTOH if terminal width is correct AND terminal does NOT
363     * have automargin (IOW: it is moving cursor to next line
364     * by itself (which is wrong for VT-10x terminals)),
365     * this will break things: there will be one extra empty line */
366     puts("\r"); /* + implicit '\n' */
367     #else
368 niro 1123 /* VT-10x terminals don't wrap cursor to next line when last char
369     * on the line is printed - cursor stays "over" this char.
370     * Need to print _next_ char too (first one to appear on next line)
371     * to make cursor move down to next line.
372     */
373     /* Works ok only if cmdedit_termw is correct. */
374     c = command_ps[cursor];
375     if (c == BB_NUL)
376     c = ' ';
377     BB_PUTCHAR(c);
378 niro 816 bb_putchar('\b');
379     #endif
380 niro 1123 cmdedit_y++;
381     if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
382     width = 0;
383     } else { /* ofs_to_right > 0 */
384     /* wide char c didn't fit on prev line */
385     BB_PUTCHAR(c);
386     }
387     cmdedit_x = width;
388 niro 816 }
389     }
390    
391     /* Move to end of line (by printing all chars till the end) */
392 niro 1123 static void put_till_end_and_adv_cursor(void)
393 niro 816 {
394     while (cursor < command_len)
395 niro 1123 put_cur_glyph_and_inc_cursor();
396 niro 816 }
397    
398     /* Go to the next line */
399     static void goto_new_line(void)
400     {
401 niro 1123 put_till_end_and_adv_cursor();
402     if (cmdedit_x != 0)
403 niro 816 bb_putchar('\n');
404     }
405    
406 niro 1123 static void beep(void)
407 niro 816 {
408 niro 1123 bb_putchar('\007');
409 niro 816 }
410    
411 niro 1123 static void put_prompt(void)
412 niro 816 {
413 niro 1123 unsigned w;
414    
415     fputs(cmdedit_prompt, stdout);
416     fflush_all();
417     cursor = 0;
418     w = cmdedit_termw; /* read volatile var once */
419     cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
420     cmdedit_x = cmdedit_prmt_len % w;
421 niro 816 }
422    
423     /* Move back one character */
424     /* (optimized for slow terminals) */
425     static void input_backward(unsigned num)
426     {
427     if (num > cursor)
428     num = cursor;
429 niro 1123 if (num == 0)
430 niro 816 return;
431     cursor -= num;
432    
433 niro 1123 if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS)
434     && unicode_status == UNICODE_ON
435     ) {
436     /* correct NUM to be equal to _screen_ width */
437     int n = num;
438     num = 0;
439     while (--n >= 0)
440     adjust_width_and_validate_wc(&num, command_ps[cursor + n]);
441     if (num == 0)
442     return;
443     }
444    
445 niro 816 if (cmdedit_x >= num) {
446     cmdedit_x -= num;
447     if (num <= 4) {
448     /* This is longer by 5 bytes on x86.
449     * Also gets miscompiled for ARM users
450     * (busybox.net/bugs/view.php?id=2274).
451     * printf(("\b\b\b\b" + 4) - num);
452     * return;
453     */
454     do {
455     bb_putchar('\b');
456     } while (--num);
457     return;
458     }
459     printf("\033[%uD", num);
460     return;
461     }
462    
463     /* Need to go one or more lines up */
464 niro 1123 if (ENABLE_UNICODE_WIDE_WCHARS) {
465     /* With wide chars, it is hard to "backtrack"
466     * and reliably figure out where to put cursor.
467     * Example (<> is a wide char; # is an ordinary char, _ cursor):
468     * |prompt: <><> |
469     * |<><><><><><> |
470     * |_ |
471     * and user presses left arrow. num = 1, cmdedit_x = 0,
472     * We need to go up one line, and then - how do we know that
473     * we need to go *10* positions to the right? Because
474     * |prompt: <>#<>|
475     * |<><><>#<><><>|
476     * |_ |
477     * in this situation we need to go *11* positions to the right.
478     *
479     * A simpler thing to do is to redraw everything from the start
480     * up to new cursor position (which is already known):
481     */
482     unsigned sv_cursor;
483     /* go to 1st column; go up to first line */
484     printf("\r" "\033[%uA", cmdedit_y);
485     cmdedit_y = 0;
486     sv_cursor = cursor;
487     put_prompt(); /* sets cursor to 0 */
488     while (cursor < sv_cursor)
489     put_cur_glyph_and_inc_cursor();
490     } else {
491     int lines_up;
492     unsigned width;
493     /* num = chars to go back from the beginning of current line: */
494     num -= cmdedit_x;
495     width = cmdedit_termw; /* read volatile var once */
496     /* num=1...w: one line up, w+1...2w: two, etc: */
497     lines_up = 1 + (num - 1) / width;
498     cmdedit_x = (width * cmdedit_y - num) % width;
499     cmdedit_y -= lines_up;
500     /* go to 1st column; go up */
501     printf("\r" "\033[%uA", lines_up);
502     /* go to correct column.
503     * xterm, konsole, Linux VT interpret 0 as 1 below! wow.
504     * need to *make sure* we skip it if cmdedit_x == 0 */
505     if (cmdedit_x)
506     printf("\033[%uC", cmdedit_x);
507 niro 816 }
508     }
509    
510     /* draw prompt, editor line, and clear tail */
511     static void redraw(int y, int back_cursor)
512     {
513 niro 1123 if (y > 0) /* up y lines */
514 niro 984 printf("\033[%uA", y);
515 niro 816 bb_putchar('\r');
516     put_prompt();
517 niro 1123 put_till_end_and_adv_cursor();
518     printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
519 niro 816 input_backward(back_cursor);
520     }
521    
522     /* Delete the char in front of the cursor, optionally saving it
523     * for later putback */
524     #if !ENABLE_FEATURE_EDITING_VI
525     static void input_delete(void)
526     #define input_delete(save) input_delete()
527     #else
528     static void input_delete(int save)
529     #endif
530     {
531     int j = cursor;
532    
533     if (j == (int)command_len)
534     return;
535    
536     #if ENABLE_FEATURE_EDITING_VI
537     if (save) {
538     if (newdelflag) {
539     delptr = delbuf;
540     newdelflag = 0;
541     }
542     if ((delptr - delbuf) < DELBUFSIZ)
543     *delptr++ = command_ps[j];
544     }
545     #endif
546    
547 niro 984 memmove(command_ps + j, command_ps + j + 1,
548     /* (command_len + 1 [because of NUL]) - (j + 1)
549     * simplified into (command_len - j) */
550     (command_len - j) * sizeof(command_ps[0]));
551 niro 816 command_len--;
552 niro 1123 put_till_end_and_adv_cursor();
553     /* Last char is still visible, erase it (and more) */
554     printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
555 niro 816 input_backward(cursor - j); /* back to old pos cursor */
556     }
557    
558     #if ENABLE_FEATURE_EDITING_VI
559     static void put(void)
560     {
561     int ocursor;
562     int j = delptr - delbuf;
563    
564     if (j == 0)
565     return;
566     ocursor = cursor;
567     /* open hole and then fill it */
568 niro 984 memmove(command_ps + cursor + j, command_ps + cursor,
569     (command_len - cursor + 1) * sizeof(command_ps[0]));
570     memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0]));
571 niro 816 command_len += j;
572 niro 1123 put_till_end_and_adv_cursor();
573 niro 816 input_backward(cursor - ocursor - j + 1); /* at end of new text */
574     }
575     #endif
576    
577     /* Delete the char in back of the cursor */
578     static void input_backspace(void)
579     {
580     if (cursor > 0) {
581     input_backward(1);
582     input_delete(0);
583     }
584     }
585    
586     /* Move forward one character */
587     static void input_forward(void)
588     {
589     if (cursor < command_len)
590 niro 1123 put_cur_glyph_and_inc_cursor();
591 niro 816 }
592    
593     #if ENABLE_FEATURE_TAB_COMPLETION
594    
595     static void free_tab_completion_data(void)
596     {
597     if (matches) {
598     while (num_matches)
599     free(matches[--num_matches]);
600     free(matches);
601     matches = NULL;
602     }
603     }
604    
605     static void add_match(char *matched)
606     {
607     matches = xrealloc_vector(matches, 4, num_matches);
608     matches[num_matches] = matched;
609     num_matches++;
610     }
611    
612     #if ENABLE_FEATURE_USERNAME_COMPLETION
613 niro 1179 /* Replace "~user/..." with "/homedir/...".
614     * The parameter is malloced, free it or return it
615     * unchanged if no user is matched.
616     */
617     static char *username_path_completion(char *ud)
618 niro 816 {
619     struct passwd *entry;
620 niro 1179 char *tilde_name = ud;
621     char *home = NULL;
622    
623     ud++; /* skip ~ */
624     if (*ud == '/') { /* "~/..." */
625     home = home_pwd_buf;
626     } else {
627     /* "~user/..." */
628     ud = strchr(ud, '/');
629     *ud = '\0'; /* "~user" */
630     entry = getpwnam(tilde_name + 1);
631     *ud = '/'; /* restore "~user/..." */
632     if (entry)
633     home = entry->pw_dir;
634     }
635     if (home) {
636     ud = concat_path_file(home, ud);
637     free(tilde_name);
638     tilde_name = ud;
639     }
640     return tilde_name;
641     }
642    
643     /* ~use<tab> - find all users with this prefix */
644     static NOINLINE void username_completion(const char *ud)
645     {
646     /* Using _r function to avoid pulling in static buffers */
647     char line_buff[256];
648     struct passwd pwd;
649     struct passwd *result;
650 niro 816 int userlen;
651    
652 niro 1179 ud++; /* skip ~ */
653 niro 816 userlen = strlen(ud);
654    
655 niro 1179 setpwent();
656     while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
657     /* Null usernames should result in all users as possible completions. */
658     if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
659     add_match(xasprintf("~%s/", pwd.pw_name));
660 niro 816 }
661     }
662 niro 1179 endpwent();
663 niro 816 }
664     #endif /* FEATURE_COMMAND_USERNAME_COMPLETION */
665    
666     enum {
667     FIND_EXE_ONLY = 0,
668     FIND_DIR_ONLY = 1,
669     FIND_FILE_ONLY = 2,
670     };
671    
672 niro 1179 static int path_parse(char ***p)
673 niro 816 {
674     int npth;
675     const char *pth;
676     char *tmp;
677     char **res;
678    
679     if (state->flags & WITH_PATH_LOOKUP)
680     pth = state->path_lookup;
681     else
682     pth = getenv("PATH");
683 niro 1179
684     /* PATH="" or PATH=":"? */
685 niro 816 if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
686     return 1;
687    
688     tmp = (char*)pth;
689     npth = 1; /* path component count */
690     while (1) {
691     tmp = strchr(tmp, ':');
692     if (!tmp)
693     break;
694 niro 1179 tmp++;
695     if (*tmp == '\0')
696 niro 816 break; /* :<empty> */
697     npth++;
698     }
699    
700 niro 1179 *p = res = xmalloc(npth * sizeof(res[0]));
701 niro 816 res[0] = tmp = xstrdup(pth);
702     npth = 1;
703     while (1) {
704     tmp = strchr(tmp, ':');
705     if (!tmp)
706     break;
707     *tmp++ = '\0'; /* ':' -> '\0' */
708     if (*tmp == '\0')
709     break; /* :<empty> */
710     res[npth++] = tmp;
711     }
712     return npth;
713     }
714    
715     static void exe_n_cwd_tab_completion(char *command, int type)
716     {
717     char *path1[1];
718     char **paths = path1;
719     int npaths;
720     int i;
721 niro 1179 char *pfind;
722     char *dirbuf = NULL;
723 niro 816
724     npaths = 1;
725     path1[0] = (char*)".";
726    
727 niro 1179 pfind = strrchr(command, '/');
728     if (!pfind) {
729     if (type == FIND_EXE_ONLY)
730     npaths = path_parse(&paths);
731 niro 816 pfind = command;
732     } else {
733 niro 1179 /* point to 'l' in "..../last_component" */
734     pfind++;
735 niro 816 /* dirbuf = ".../.../.../" */
736 niro 1179 dirbuf = xstrndup(command, pfind - command);
737 niro 816 #if ENABLE_FEATURE_USERNAME_COMPLETION
738     if (dirbuf[0] == '~') /* ~/... or ~user/... */
739 niro 1179 dirbuf = username_path_completion(dirbuf);
740 niro 816 #endif
741 niro 1179 path1[0] = dirbuf;
742 niro 816 }
743    
744     for (i = 0; i < npaths; i++) {
745 niro 1179 DIR *dir;
746     struct dirent *next;
747     struct stat st;
748     char *found;
749    
750 niro 816 dir = opendir(paths[i]);
751     if (!dir)
752     continue; /* don't print an error */
753    
754     while ((next = readdir(dir)) != NULL) {
755 niro 1179 const char *name_found = next->d_name;
756 niro 816
757 niro 1179 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
758     if (!pfind[0] && DOT_OR_DOTDOT(name_found))
759 niro 816 continue;
760 niro 1179 /* match? */
761     if (strncmp(name_found, pfind, strlen(pfind)) != 0)
762     continue; /* no */
763    
764     found = concat_path_file(paths[i], name_found);
765 niro 816 /* NB: stat() first so that we see is it a directory;
766     * but if that fails, use lstat() so that
767     * we still match dangling links */
768     if (stat(found, &st) && lstat(found, &st))
769 niro 1179 goto cont; /* hmm, remove in progress? */
770    
771     /* save only name if we scan PATH */
772 niro 816 if (paths[i] != dirbuf)
773 niro 1179 strcpy(found, name_found);
774 niro 816
775     if (S_ISDIR(st.st_mode)) {
776 niro 1179 unsigned len1 = strlen(found);
777 niro 816 /* name is a directory */
778     if (found[len1-1] != '/') {
779 niro 1179 found = xrealloc(found, len1 + 2);
780 niro 816 found[len1] = '/';
781 niro 1179 found[len1 + 1] = '\0';
782 niro 816 }
783     } else {
784 niro 1179 /* skip files if looking for dirs only (example: cd) */
785 niro 816 if (type == FIND_DIR_ONLY)
786     goto cont;
787     }
788 niro 1179 /* add it to the list */
789 niro 816 add_match(found);
790     continue;
791     cont:
792     free(found);
793     }
794     closedir(dir);
795 niro 1179 } /* for every path */
796    
797 niro 816 if (paths != path1) {
798     free(paths[0]); /* allocated memory is only in first member */
799     free(paths);
800     }
801 niro 1179 free(dirbuf);
802 niro 816 }
803    
804 niro 984 /* QUOT is used on elements of int_buf[], which are bytes,
805     * not Unicode chars. Therefore it works correctly even in Unicode mode.
806     */
807 niro 816 #define QUOT (UCHAR_MAX+1)
808    
809 niro 984 #define int_buf (S.find_match__int_buf)
810     #define pos_buf (S.find_match__pos_buf)
811     /* is must be <= in */
812     static void collapse_pos(int is, int in)
813 niro 816 {
814 niro 1179 memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in) * sizeof(int_buf[0]));
815     memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in) * sizeof(pos_buf[0]));
816 niro 984 }
817 niro 1179 /* On entry, matchBuf contains everything up to cursor at the moment <tab>
818     * was pressed. This function looks at it, figures out what part of it
819     * constitutes the command/file/directory prefix to use for completion,
820     * and rewrites matchBuf to contain only that part.
821     */
822     static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
823 niro 984 {
824 niro 816 int i, j;
825     int command_mode;
826     int c, c2;
827 niro 1179 /* Were local, but it used too much stack */
828 niro 816 /* int16_t int_buf[MAX_LINELEN + 1]; */
829     /* int16_t pos_buf[MAX_LINELEN + 1]; */
830    
831     /* set to integer dimension characters and own positions */
832     for (i = 0;; i++) {
833     int_buf[i] = (unsigned char)matchBuf[i];
834     if (int_buf[i] == 0) {
835 niro 984 pos_buf[i] = -1; /* end-fo-line indicator */
836 niro 816 break;
837     }
838     pos_buf[i] = i;
839     }
840    
841     /* mask \+symbol and convert '\t' to ' ' */
842 niro 1123 for (i = j = 0; matchBuf[i]; i++, j++) {
843 niro 816 if (matchBuf[i] == '\\') {
844     collapse_pos(j, j + 1);
845     int_buf[j] |= QUOT;
846     i++;
847     }
848 niro 1123 }
849 niro 816 /* mask "symbols" or 'symbols' */
850     c2 = 0;
851     for (i = 0; int_buf[i]; i++) {
852     c = int_buf[i];
853     if (c == '\'' || c == '"') {
854     if (c2 == 0)
855     c2 = c;
856     else {
857     if (c == c2)
858     c2 = 0;
859     else
860     int_buf[i] |= QUOT;
861     }
862     } else if (c2 != 0 && c != '$')
863     int_buf[i] |= QUOT;
864     }
865    
866     /* skip commands with arguments if line has commands delimiters */
867 niro 1179 /* ';' ';;' '&' '|' '&&' '||' but '>&' '<&' '>|' */
868 niro 816 for (i = 0; int_buf[i]; i++) {
869 niro 1179 int n;
870 niro 816 c = int_buf[i];
871     c2 = int_buf[i + 1];
872     j = i ? int_buf[i - 1] : -1;
873 niro 1179 n = 0;
874 niro 816 if (c == ';' || c == '&' || c == '|') {
875 niro 1179 n = 1 + (c == c2);
876 niro 816 if (c == '&') {
877     if (j == '>' || j == '<')
878 niro 1179 n = 0;
879 niro 816 } else if (c == '|' && j == '>')
880 niro 1179 n = 0;
881 niro 816 }
882 niro 1179 if (n) {
883     collapse_pos(0, i + n);
884 niro 984 i = -1; /* hack incremet */
885 niro 816 }
886     }
887     /* collapse `command...` */
888 niro 984 for (i = 0; int_buf[i]; i++) {
889 niro 816 if (int_buf[i] == '`') {
890     for (j = i + 1; int_buf[j]; j++)
891     if (int_buf[j] == '`') {
892     collapse_pos(i, j + 1);
893     j = 0;
894     break;
895     }
896     if (j) {
897 niro 984 /* not found closing ` - command mode, collapse all previous */
898 niro 816 collapse_pos(0, i + 1);
899     break;
900     } else
901 niro 984 i--; /* hack incremet */
902 niro 816 }
903 niro 984 }
904 niro 816
905     /* collapse (command...(command...)...) or {command...{command...}...} */
906 niro 984 c = 0; /* "recursive" level */
907 niro 816 c2 = 0;
908 niro 984 for (i = 0; int_buf[i]; i++) {
909 niro 816 if (int_buf[i] == '(' || int_buf[i] == '{') {
910     if (int_buf[i] == '(')
911     c++;
912     else
913     c2++;
914     collapse_pos(0, i + 1);
915 niro 984 i = -1; /* hack incremet */
916 niro 816 }
917 niro 984 }
918     for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) {
919 niro 816 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
920     if (int_buf[i] == ')')
921     c--;
922     else
923     c2--;
924     collapse_pos(0, i + 1);
925 niro 984 i = -1; /* hack incremet */
926 niro 816 }
927 niro 984 }
928 niro 816
929     /* skip first not quote space */
930     for (i = 0; int_buf[i]; i++)
931     if (int_buf[i] != ' ')
932     break;
933     if (i)
934     collapse_pos(0, i);
935    
936     /* set find mode for completion */
937     command_mode = FIND_EXE_ONLY;
938 niro 984 for (i = 0; int_buf[i]; i++) {
939 niro 816 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
940     if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
941     && matchBuf[pos_buf[0]] == 'c'
942     && matchBuf[pos_buf[1]] == 'd'
943     ) {
944     command_mode = FIND_DIR_ONLY;
945     } else {
946     command_mode = FIND_FILE_ONLY;
947     break;
948     }
949     }
950 niro 984 }
951 niro 1179 for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
952     continue;
953 niro 816 /* find last word */
954     for (--i; i >= 0; i--) {
955     c = int_buf[i];
956     if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
957     collapse_pos(0, i + 1);
958     break;
959     }
960     }
961     /* skip first not quoted '\'' or '"' */
962     for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
963 niro 1179 continue;
964 niro 816 /* collapse quote or unquote // or /~ */
965     while ((int_buf[i] & ~QUOT) == '/'
966     && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
967     ) {
968     i++;
969     }
970    
971     /* set only match and destroy quotes */
972     j = 0;
973     for (c = 0; pos_buf[i] >= 0; i++) {
974     matchBuf[c++] = matchBuf[pos_buf[i]];
975     j = pos_buf[i] + 1;
976     }
977     matchBuf[c] = '\0';
978     /* old length matchBuf with quotes symbols */
979     *len_with_quotes = j ? j - pos_buf[0] : 0;
980    
981     return command_mode;
982 niro 984 }
983 niro 816 #undef int_buf
984     #undef pos_buf
985    
986     /*
987     * display by column (original idea from ls applet,
988     * very optimized by me :)
989     */
990     static void showfiles(void)
991     {
992     int ncols, row;
993     int column_width = 0;
994     int nfiles = num_matches;
995     int nrows = nfiles;
996     int l;
997    
998 niro 984 /* find the longest file name - use that as the column width */
999 niro 816 for (row = 0; row < nrows; row++) {
1000 niro 1123 l = unicode_strwidth(matches[row]);
1001 niro 816 if (column_width < l)
1002     column_width = l;
1003     }
1004     column_width += 2; /* min space for columns */
1005     ncols = cmdedit_termw / column_width;
1006    
1007     if (ncols > 1) {
1008     nrows /= ncols;
1009     if (nfiles % ncols)
1010     nrows++; /* round up fractionals */
1011     } else {
1012     ncols = 1;
1013     }
1014     for (row = 0; row < nrows; row++) {
1015     int n = row;
1016     int nc;
1017    
1018     for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
1019     printf("%s%-*s", matches[n],
1020 niro 1123 (int)(column_width - unicode_strwidth(matches[n])), ""
1021 niro 984 );
1022 niro 816 }
1023 niro 1123 if (ENABLE_UNICODE_SUPPORT)
1024     puts(printable_string(NULL, matches[n]));
1025     else
1026     puts(matches[n]);
1027 niro 816 }
1028     }
1029    
1030     static char *add_quote_for_spec_chars(char *found)
1031     {
1032     int l = 0;
1033 niro 984 char *s = xzalloc((strlen(found) + 1) * 2);
1034 niro 816
1035     while (*found) {
1036 niro 984 if (strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", *found))
1037 niro 816 s[l++] = '\\';
1038     s[l++] = *found++;
1039     }
1040 niro 984 /* s[l] = '\0'; - already is */
1041 niro 816 return s;
1042     }
1043    
1044     /* Do TAB completion */
1045     static void input_tab(smallint *lastWasTab)
1046     {
1047     if (!(state->flags & TAB_COMPLETION))
1048     return;
1049    
1050     if (!*lastWasTab) {
1051     char *tmp, *tmp1;
1052     size_t len_found;
1053     /* char matchBuf[MAX_LINELEN]; */
1054     #define matchBuf (S.input_tab__matchBuf)
1055     int find_type;
1056     int recalc_pos;
1057 niro 1123 #if ENABLE_UNICODE_SUPPORT
1058 niro 984 /* cursor pos in command converted to multibyte form */
1059     int cursor_mb;
1060     #endif
1061 niro 816
1062     *lastWasTab = TRUE; /* flop trigger */
1063    
1064 niro 984 /* Make a local copy of the string --
1065     * up to the position of the cursor */
1066 niro 1179 #if !ENABLE_UNICODE_SUPPORT
1067 niro 984 save_string(matchBuf, cursor + 1);
1068 niro 1179 #else
1069     {
1070     CHAR_T wc = command_ps[cursor];
1071     command_ps[cursor] = 0;
1072     save_string(matchBuf, MAX_LINELEN);
1073     command_ps[cursor] = wc;
1074     cursor_mb = strlen(matchBuf);
1075     }
1076 niro 984 #endif
1077     tmp = matchBuf;
1078 niro 816
1079 niro 1179 find_type = build_match_prefix(matchBuf, &recalc_pos);
1080 niro 816
1081     /* Free up any memory already allocated */
1082     free_tab_completion_data();
1083    
1084     #if ENABLE_FEATURE_USERNAME_COMPLETION
1085     /* If the word starts with `~' and there is no slash in the word,
1086     * then try completing this word as a username. */
1087     if (state->flags & USERNAME_COMPLETION)
1088 niro 984 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL)
1089 niro 1179 username_completion(matchBuf);
1090 niro 816 #endif
1091     /* Try to match any executable in our path and everything
1092     * in the current working directory */
1093     if (!matches)
1094     exe_n_cwd_tab_completion(matchBuf, find_type);
1095     /* Sort, then remove any duplicates found */
1096     if (matches) {
1097     unsigned i;
1098 niro 1179 unsigned n = 0;
1099 niro 816 qsort_string_vector(matches, num_matches);
1100     for (i = 0; i < num_matches - 1; ++i) {
1101     if (matches[i] && matches[i+1]) { /* paranoia */
1102     if (strcmp(matches[i], matches[i+1]) == 0) {
1103     free(matches[i]);
1104     matches[i] = NULL; /* paranoia */
1105     } else {
1106     matches[n++] = matches[i];
1107     }
1108     }
1109     }
1110 niro 1179 matches[n++] = matches[i];
1111     num_matches = n;
1112 niro 816 }
1113     /* Did we find exactly one match? */
1114 niro 1179 if (num_matches != 1) { /* no */
1115 niro 816 beep();
1116     if (!matches)
1117 niro 1179 return; /* no matches at all */
1118 niro 816 /* find minimal match */
1119     tmp1 = xstrdup(matches[0]);
1120 niro 984 for (tmp = tmp1; *tmp; tmp++) {
1121     for (len_found = 1; len_found < num_matches; len_found++) {
1122     if (matches[len_found][tmp - tmp1] != *tmp) {
1123 niro 816 *tmp = '\0';
1124     break;
1125     }
1126 niro 984 }
1127     }
1128 niro 1179 if (*tmp1 == '\0') { /* have unique pfx? */
1129     free(tmp1); /* no */
1130 niro 816 return;
1131     }
1132     tmp = add_quote_for_spec_chars(tmp1);
1133     free(tmp1);
1134 niro 1179 len_found = strlen(tmp);
1135     } else { /* exactly one match */
1136 niro 816 tmp = add_quote_for_spec_chars(matches[0]);
1137     /* for next completion current found */
1138     *lastWasTab = FALSE;
1139    
1140     len_found = strlen(tmp);
1141     if (tmp[len_found-1] != '/') {
1142     tmp[len_found] = ' ';
1143 niro 1179 tmp[++len_found] = '\0';
1144 niro 816 }
1145     }
1146 niro 984
1147 niro 1123 #if !ENABLE_UNICODE_SUPPORT
1148 niro 984 /* have space to place the match? */
1149     /* The result consists of three parts with these lengths: */
1150     /* (cursor - recalc_pos) + len_found + (command_len - cursor) */
1151     /* it simplifies into: */
1152     if ((int)(len_found + command_len - recalc_pos) < S.maxsize) {
1153     /* save tail */
1154 niro 816 strcpy(matchBuf, command_ps + cursor);
1155 niro 984 /* add match and tail */
1156     sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf);
1157 niro 816 command_len = strlen(command_ps);
1158 niro 984 /* new pos */
1159     recalc_pos = cursor - recalc_pos + len_found;
1160     /* write out the matched command */
1161 niro 816 redraw(cmdedit_y, command_len - recalc_pos);
1162     }
1163 niro 984 #else
1164     {
1165     char command[MAX_LINELEN];
1166     int len = save_string(command, sizeof(command));
1167     /* have space to place the match? */
1168     /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */
1169     if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) {
1170     /* save tail */
1171     strcpy(matchBuf, command + cursor_mb);
1172     /* where do we want to have cursor after all? */
1173     strcpy(&command[cursor_mb - recalc_pos], tmp);
1174     len = load_string(command, S.maxsize);
1175     /* add match and tail */
1176     sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf);
1177     command_len = load_string(command, S.maxsize);
1178     /* write out the matched command */
1179 niro 1179 /* paranoia: load_string can return 0 on conv error,
1180     * prevent passing len = (0 - 12) to redraw */
1181     len = command_len - len;
1182     redraw(cmdedit_y, len >= 0 ? len : 0);
1183 niro 984 }
1184     }
1185     #endif
1186 niro 816 free(tmp);
1187     #undef matchBuf
1188     } else {
1189     /* Ok -- the last char was a TAB. Since they
1190     * just hit TAB again, print a list of all the
1191     * available choices... */
1192     if (matches && num_matches > 0) {
1193 niro 984 /* changed by goto_new_line() */
1194     int sav_cursor = cursor;
1195 niro 816
1196     /* Go to the next line */
1197     goto_new_line();
1198     showfiles();
1199     redraw(0, command_len - sav_cursor);
1200     }
1201     }
1202     }
1203    
1204     #endif /* FEATURE_COMMAND_TAB_COMPLETION */
1205    
1206    
1207 niro 984 line_input_t* FAST_FUNC new_line_input_t(int flags)
1208     {
1209     line_input_t *n = xzalloc(sizeof(*n));
1210     n->flags = flags;
1211     return n;
1212     }
1213    
1214    
1215 niro 816 #if MAX_HISTORY > 0
1216    
1217     static void save_command_ps_at_cur_history(void)
1218     {
1219 niro 984 if (command_ps[0] != BB_NUL) {
1220 niro 816 int cur = state->cur_history;
1221     free(state->history[cur]);
1222 niro 984
1223 niro 1123 # if ENABLE_UNICODE_SUPPORT
1224 niro 984 {
1225     char tbuf[MAX_LINELEN];
1226     save_string(tbuf, sizeof(tbuf));
1227     state->history[cur] = xstrdup(tbuf);
1228     }
1229     # else
1230 niro 816 state->history[cur] = xstrdup(command_ps);
1231 niro 984 # endif
1232 niro 816 }
1233     }
1234    
1235     /* state->flags is already checked to be nonzero */
1236     static int get_previous_history(void)
1237     {
1238     if ((state->flags & DO_HISTORY) && state->cur_history) {
1239     save_command_ps_at_cur_history();
1240     state->cur_history--;
1241     return 1;
1242     }
1243     beep();
1244     return 0;
1245     }
1246    
1247     static int get_next_history(void)
1248     {
1249     if (state->flags & DO_HISTORY) {
1250     if (state->cur_history < state->cnt_history) {
1251     save_command_ps_at_cur_history(); /* save the current history line */
1252     return ++state->cur_history;
1253     }
1254     }
1255     beep();
1256     return 0;
1257     }
1258    
1259 niro 984 # if ENABLE_FEATURE_EDITING_SAVEHISTORY
1260     /* We try to ensure that concurrent additions to the history
1261     * do not overwrite each other.
1262     * Otherwise shell users get unhappy.
1263     *
1264     * History file is trimmed lazily, when it grows several times longer
1265     * than configured MAX_HISTORY lines.
1266     */
1267    
1268     static void free_line_input_t(line_input_t *n)
1269     {
1270     int i = n->cnt_history;
1271     while (i > 0)
1272     free(n->history[--i]);
1273     free(n);
1274     }
1275    
1276 niro 816 /* state->flags is already checked to be nonzero */
1277 niro 984 static void load_history(line_input_t *st_parm)
1278 niro 816 {
1279 niro 984 char *temp_h[MAX_HISTORY];
1280     char *line;
1281 niro 816 FILE *fp;
1282 niro 984 unsigned idx, i, line_len;
1283 niro 816
1284     /* NB: do not trash old history if file can't be opened */
1285    
1286 niro 984 fp = fopen_for_read(st_parm->hist_file);
1287 niro 816 if (fp) {
1288     /* clean up old history */
1289 niro 984 for (idx = st_parm->cnt_history; idx > 0;) {
1290     idx--;
1291     free(st_parm->history[idx]);
1292     st_parm->history[idx] = NULL;
1293 niro 816 }
1294    
1295 niro 984 /* fill temp_h[], retaining only last MAX_HISTORY lines */
1296     memset(temp_h, 0, sizeof(temp_h));
1297     st_parm->cnt_history_in_file = idx = 0;
1298     while ((line = xmalloc_fgetline(fp)) != NULL) {
1299     if (line[0] == '\0') {
1300     free(line);
1301 niro 816 continue;
1302     }
1303 niro 984 free(temp_h[idx]);
1304     temp_h[idx] = line;
1305     st_parm->cnt_history_in_file++;
1306     idx++;
1307     if (idx == MAX_HISTORY)
1308     idx = 0;
1309 niro 816 }
1310     fclose(fp);
1311 niro 984
1312     /* find first non-NULL temp_h[], if any */
1313     if (st_parm->cnt_history_in_file) {
1314     while (temp_h[idx] == NULL) {
1315     idx++;
1316     if (idx == MAX_HISTORY)
1317     idx = 0;
1318     }
1319     }
1320    
1321     /* copy temp_h[] to st_parm->history[] */
1322     for (i = 0; i < MAX_HISTORY;) {
1323     line = temp_h[idx];
1324     if (!line)
1325     break;
1326     idx++;
1327     if (idx == MAX_HISTORY)
1328     idx = 0;
1329     line_len = strlen(line);
1330     if (line_len >= MAX_LINELEN)
1331     line[MAX_LINELEN-1] = '\0';
1332     st_parm->history[i++] = line;
1333     }
1334     st_parm->cnt_history = i;
1335 niro 816 }
1336     }
1337    
1338     /* state->flags is already checked to be nonzero */
1339 niro 984 static void save_history(char *str)
1340 niro 816 {
1341 niro 984 int fd;
1342     int len, len2;
1343 niro 816
1344 niro 984 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666);
1345     if (fd < 0)
1346     return;
1347     xlseek(fd, 0, SEEK_END); /* paranoia */
1348     len = strlen(str);
1349     str[len] = '\n'; /* we (try to) do atomic write */
1350     len2 = full_write(fd, str, len + 1);
1351     str[len] = '\0';
1352     close(fd);
1353     if (len2 != len + 1)
1354     return; /* "wtf?" */
1355    
1356     /* did we write so much that history file needs trimming? */
1357     state->cnt_history_in_file++;
1358     if (state->cnt_history_in_file > MAX_HISTORY * 4) {
1359     FILE *fp;
1360     char *new_name;
1361     line_input_t *st_temp;
1362 niro 816 int i;
1363    
1364 niro 984 /* we may have concurrently written entries from others.
1365     * load them */
1366     st_temp = new_line_input_t(state->flags);
1367     st_temp->hist_file = state->hist_file;
1368     load_history(st_temp);
1369    
1370     /* write out temp file and replace hist_file atomically */
1371     new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
1372     fp = fopen_for_write(new_name);
1373     if (fp) {
1374     for (i = 0; i < st_temp->cnt_history; i++)
1375     fprintf(fp, "%s\n", st_temp->history[i]);
1376     fclose(fp);
1377     if (rename(new_name, state->hist_file) == 0)
1378     state->cnt_history_in_file = st_temp->cnt_history;
1379 niro 816 }
1380 niro 984 free(new_name);
1381     free_line_input_t(st_temp);
1382 niro 816 }
1383     }
1384 niro 984 # else
1385     # define load_history(a) ((void)0)
1386     # define save_history(a) ((void)0)
1387     # endif /* FEATURE_COMMAND_SAVEHISTORY */
1388 niro 816
1389 niro 984 static void remember_in_history(char *str)
1390 niro 816 {
1391     int i;
1392    
1393     if (!(state->flags & DO_HISTORY))
1394     return;
1395     if (str[0] == '\0')
1396     return;
1397     i = state->cnt_history;
1398     /* Don't save dupes */
1399     if (i && strcmp(state->history[i-1], str) == 0)
1400     return;
1401    
1402     free(state->history[MAX_HISTORY]); /* redundant, paranoia */
1403     state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */
1404    
1405     /* If history[] is full, remove the oldest command */
1406     /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */
1407     if (i >= MAX_HISTORY) {
1408     free(state->history[0]);
1409     for (i = 0; i < MAX_HISTORY-1; i++)
1410     state->history[i] = state->history[i+1];
1411     /* i == MAX_HISTORY-1 */
1412     }
1413     /* i <= MAX_HISTORY-1 */
1414     state->history[i++] = xstrdup(str);
1415     /* i <= MAX_HISTORY */
1416     state->cur_history = i;
1417     state->cnt_history = i;
1418 niro 984 # if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
1419 niro 816 if ((state->flags & SAVE_HISTORY) && state->hist_file)
1420 niro 984 save_history(str);
1421     # endif
1422     IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
1423 niro 816 }
1424    
1425     #else /* MAX_HISTORY == 0 */
1426 niro 984 # define remember_in_history(a) ((void)0)
1427 niro 816 #endif /* MAX_HISTORY */
1428    
1429    
1430 niro 984 #if ENABLE_FEATURE_EDITING_VI
1431 niro 816 /*
1432     * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
1433     */
1434     static void
1435 niro 984 vi_Word_motion(int eat)
1436 niro 816 {
1437 niro 984 CHAR_T *command = command_ps;
1438    
1439     while (cursor < command_len && !BB_isspace(command[cursor]))
1440 niro 816 input_forward();
1441 niro 984 if (eat) while (cursor < command_len && BB_isspace(command[cursor]))
1442 niro 816 input_forward();
1443     }
1444    
1445     static void
1446 niro 984 vi_word_motion(int eat)
1447 niro 816 {
1448 niro 984 CHAR_T *command = command_ps;
1449    
1450     if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
1451 niro 816 while (cursor < command_len
1452 niro 984 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
1453     ) {
1454 niro 816 input_forward();
1455 niro 984 }
1456     } else if (BB_ispunct(command[cursor])) {
1457     while (cursor < command_len && BB_ispunct(command[cursor+1]))
1458 niro 816 input_forward();
1459     }
1460    
1461     if (cursor < command_len)
1462     input_forward();
1463    
1464 niro 984 if (eat) {
1465     while (cursor < command_len && BB_isspace(command[cursor]))
1466 niro 816 input_forward();
1467 niro 984 }
1468 niro 816 }
1469    
1470     static void
1471 niro 984 vi_End_motion(void)
1472 niro 816 {
1473 niro 984 CHAR_T *command = command_ps;
1474    
1475 niro 816 input_forward();
1476 niro 984 while (cursor < command_len && BB_isspace(command[cursor]))
1477 niro 816 input_forward();
1478 niro 984 while (cursor < command_len-1 && !BB_isspace(command[cursor+1]))
1479 niro 816 input_forward();
1480     }
1481    
1482     static void
1483 niro 984 vi_end_motion(void)
1484 niro 816 {
1485 niro 984 CHAR_T *command = command_ps;
1486    
1487 niro 816 if (cursor >= command_len-1)
1488     return;
1489     input_forward();
1490 niro 984 while (cursor < command_len-1 && BB_isspace(command[cursor]))
1491 niro 816 input_forward();
1492     if (cursor >= command_len-1)
1493     return;
1494 niro 984 if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
1495 niro 816 while (cursor < command_len-1
1496 niro 984 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
1497 niro 816 ) {
1498     input_forward();
1499     }
1500 niro 984 } else if (BB_ispunct(command[cursor])) {
1501     while (cursor < command_len-1 && BB_ispunct(command[cursor+1]))
1502 niro 816 input_forward();
1503     }
1504     }
1505    
1506     static void
1507 niro 984 vi_Back_motion(void)
1508 niro 816 {
1509 niro 984 CHAR_T *command = command_ps;
1510    
1511     while (cursor > 0 && BB_isspace(command[cursor-1]))
1512 niro 816 input_backward(1);
1513 niro 984 while (cursor > 0 && !BB_isspace(command[cursor-1]))
1514 niro 816 input_backward(1);
1515     }
1516    
1517     static void
1518 niro 984 vi_back_motion(void)
1519 niro 816 {
1520 niro 984 CHAR_T *command = command_ps;
1521    
1522 niro 816 if (cursor <= 0)
1523     return;
1524     input_backward(1);
1525 niro 984 while (cursor > 0 && BB_isspace(command[cursor]))
1526 niro 816 input_backward(1);
1527     if (cursor <= 0)
1528     return;
1529 niro 984 if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
1530 niro 816 while (cursor > 0
1531 niro 984 && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_')
1532 niro 816 ) {
1533     input_backward(1);
1534     }
1535 niro 984 } else if (BB_ispunct(command[cursor])) {
1536     while (cursor > 0 && BB_ispunct(command[cursor-1]))
1537 niro 816 input_backward(1);
1538     }
1539     }
1540     #endif
1541    
1542 niro 984 /* Modelled after bash 4.0 behavior of Ctrl-<arrow> */
1543     static void ctrl_left(void)
1544     {
1545     CHAR_T *command = command_ps;
1546 niro 816
1547 niro 984 while (1) {
1548     CHAR_T c;
1549    
1550     input_backward(1);
1551     if (cursor == 0)
1552     break;
1553     c = command[cursor];
1554     if (c != ' ' && !BB_ispunct(c)) {
1555     /* we reached a "word" delimited by spaces/punct.
1556     * go to its beginning */
1557     while (1) {
1558     c = command[cursor - 1];
1559     if (c == ' ' || BB_ispunct(c))
1560     break;
1561     input_backward(1);
1562     if (cursor == 0)
1563     break;
1564     }
1565     break;
1566     }
1567     }
1568     }
1569     static void ctrl_right(void)
1570     {
1571     CHAR_T *command = command_ps;
1572    
1573     while (1) {
1574     CHAR_T c;
1575    
1576     c = command[cursor];
1577     if (c == BB_NUL)
1578     break;
1579     if (c != ' ' && !BB_ispunct(c)) {
1580     /* we reached a "word" delimited by spaces/punct.
1581     * go to its end + 1 */
1582     while (1) {
1583     input_forward();
1584     c = command[cursor];
1585     if (c == BB_NUL || c == ' ' || BB_ispunct(c))
1586     break;
1587     }
1588     break;
1589     }
1590     input_forward();
1591     }
1592     }
1593    
1594    
1595 niro 816 /*
1596     * read_line_input and its helpers
1597     */
1598    
1599 niro 984 #if ENABLE_FEATURE_EDITING_ASK_TERMINAL
1600     static void ask_terminal(void)
1601     {
1602     /* Ask terminal where is the cursor now.
1603     * lineedit_read_key handles response and corrects
1604     * our idea of current cursor position.
1605     * Testcase: run "echo -n long_line_long_line_long_line",
1606     * then type in a long, wrapping command and try to
1607     * delete it using backspace key.
1608     * Note: we print it _after_ prompt, because
1609     * prompt may contain CR. Example: PS1='\[\r\n\]\w '
1610     */
1611     /* Problem: if there is buffered input on stdin,
1612     * the response will be delivered later,
1613     * possibly to an unsuspecting application.
1614     * Testcase: "sleep 1; busybox ash" + press and hold [Enter].
1615     * Result:
1616     * ~/srcdevel/bbox/fix/busybox.t4 #
1617     * ~/srcdevel/bbox/fix/busybox.t4 #
1618     * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage
1619     * ~/srcdevel/bbox/fix/busybox.t4 #
1620     *
1621     * Checking for input with poll only makes the race narrower,
1622     * I still can trigger it. Strace:
1623     *
1624     * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33
1625     * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists
1626     * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick!
1627     * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}])
1628     * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first
1629     */
1630     struct pollfd pfd;
1631    
1632     pfd.fd = STDIN_FILENO;
1633     pfd.events = POLLIN;
1634     if (safe_poll(&pfd, 1, 0) == 0) {
1635     S.sent_ESC_br6n = 1;
1636 niro 1123 fputs("\033" "[6n", stdout);
1637 niro 984 fflush_all(); /* make terminal see it ASAP! */
1638     }
1639     }
1640     #else
1641     #define ask_terminal() ((void)0)
1642     #endif
1643    
1644 niro 816 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1645     static void parse_and_put_prompt(const char *prmt_ptr)
1646     {
1647     cmdedit_prompt = prmt_ptr;
1648     cmdedit_prmt_len = strlen(prmt_ptr);
1649     put_prompt();
1650     }
1651     #else
1652     static void parse_and_put_prompt(const char *prmt_ptr)
1653     {
1654     int prmt_len = 0;
1655     size_t cur_prmt_len = 0;
1656     char flg_not_length = '[';
1657     char *prmt_mem_ptr = xzalloc(1);
1658     char *cwd_buf = xrealloc_getcwd_or_warn(NULL);
1659     char cbuf[2];
1660     char c;
1661     char *pbuf;
1662    
1663     cmdedit_prmt_len = 0;
1664    
1665     if (!cwd_buf) {
1666     cwd_buf = (char *)bb_msg_unknown;
1667     }
1668    
1669     cbuf[1] = '\0'; /* never changes */
1670    
1671     while (*prmt_ptr) {
1672     char *free_me = NULL;
1673    
1674     pbuf = cbuf;
1675     c = *prmt_ptr++;
1676     if (c == '\\') {
1677     const char *cp = prmt_ptr;
1678     int l;
1679    
1680     c = bb_process_escape_sequence(&prmt_ptr);
1681     if (prmt_ptr == cp) {
1682     if (*cp == '\0')
1683     break;
1684     c = *prmt_ptr++;
1685    
1686     switch (c) {
1687 niro 984 # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1688 niro 816 case 'u':
1689     pbuf = user_buf ? user_buf : (char*)"";
1690     break;
1691 niro 984 # endif
1692 niro 816 case 'h':
1693     pbuf = free_me = safe_gethostname();
1694     *strchrnul(pbuf, '.') = '\0';
1695     break;
1696     case '$':
1697     c = (geteuid() == 0 ? '#' : '$');
1698     break;
1699 niro 984 # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1700 niro 816 case 'w':
1701     /* /home/user[/something] -> ~[/something] */
1702     pbuf = cwd_buf;
1703     l = strlen(home_pwd_buf);
1704     if (l != 0
1705     && strncmp(home_pwd_buf, cwd_buf, l) == 0
1706     && (cwd_buf[l]=='/' || cwd_buf[l]=='\0')
1707     && strlen(cwd_buf + l) < PATH_MAX
1708     ) {
1709     pbuf = free_me = xasprintf("~%s", cwd_buf + l);
1710     }
1711     break;
1712 niro 984 # endif
1713 niro 816 case 'W':
1714     pbuf = cwd_buf;
1715     cp = strrchr(pbuf, '/');
1716     if (cp != NULL && cp != pbuf)
1717     pbuf += (cp-pbuf) + 1;
1718     break;
1719     case '!':
1720     pbuf = free_me = xasprintf("%d", num_ok_lines);
1721     break;
1722     case 'e': case 'E': /* \e \E = \033 */
1723     c = '\033';
1724     break;
1725     case 'x': case 'X': {
1726     char buf2[4];
1727     for (l = 0; l < 3;) {
1728     unsigned h;
1729     buf2[l++] = *prmt_ptr;
1730     buf2[l] = '\0';
1731     h = strtoul(buf2, &pbuf, 16);
1732     if (h > UCHAR_MAX || (pbuf - buf2) < l) {
1733     buf2[--l] = '\0';
1734     break;
1735     }
1736     prmt_ptr++;
1737     }
1738     c = (char)strtoul(buf2, NULL, 16);
1739     if (c == 0)
1740     c = '?';
1741     pbuf = cbuf;
1742     break;
1743     }
1744     case '[': case ']':
1745     if (c == flg_not_length) {
1746     flg_not_length = (flg_not_length == '[' ? ']' : '[');
1747     continue;
1748     }
1749     break;
1750     } /* switch */
1751     } /* if */
1752     } /* if */
1753     cbuf[0] = c;
1754     cur_prmt_len = strlen(pbuf);
1755     prmt_len += cur_prmt_len;
1756     if (flg_not_length != ']')
1757     cmdedit_prmt_len += cur_prmt_len;
1758     prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
1759     free(free_me);
1760     } /* while */
1761    
1762     if (cwd_buf != (char *)bb_msg_unknown)
1763     free(cwd_buf);
1764     cmdedit_prompt = prmt_mem_ptr;
1765     put_prompt();
1766     }
1767     #endif
1768    
1769     static void cmdedit_setwidth(unsigned w, int redraw_flg)
1770     {
1771     cmdedit_termw = w;
1772     if (redraw_flg) {
1773     /* new y for current cursor */
1774     int new_y = (cursor + cmdedit_prmt_len) / w;
1775     /* redraw */
1776     redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
1777 niro 984 fflush_all();
1778 niro 816 }
1779     }
1780    
1781     static void win_changed(int nsig)
1782     {
1783 niro 1123 int sv_errno = errno;
1784 niro 816 unsigned width;
1785     get_terminal_width_height(0, &width, NULL);
1786     cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
1787     if (nsig == SIGWINCH)
1788     signal(SIGWINCH, win_changed); /* rearm ourself */
1789 niro 1123 errno = sv_errno;
1790 niro 816 }
1791    
1792 niro 984 static int lineedit_read_key(char *read_key_buffer)
1793     {
1794     int64_t ic;
1795 niro 1123 int timeout = -1;
1796     #if ENABLE_UNICODE_SUPPORT
1797 niro 984 char unicode_buf[MB_CUR_MAX + 1];
1798     int unicode_idx = 0;
1799     #endif
1800 niro 816
1801 niro 1123 while (1) {
1802     /* Wait for input. TIMEOUT = -1 makes read_key wait even
1803     * on nonblocking stdin, TIMEOUT = 50 makes sure we won't
1804     * insist on full MB_CUR_MAX buffer to declare input like
1805     * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
1806     *
1807     * Note: read_key sets errno to 0 on success.
1808     */
1809     ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
1810     if (errno) {
1811     #if ENABLE_UNICODE_SUPPORT
1812     if (errno == EAGAIN && unicode_idx != 0)
1813     goto pushback;
1814 niro 984 #endif
1815 niro 1123 break;
1816 niro 984 }
1817 niro 816
1818 niro 984 #if ENABLE_FEATURE_EDITING_ASK_TERMINAL
1819     if ((int32_t)ic == KEYCODE_CURSOR_POS
1820     && S.sent_ESC_br6n
1821     ) {
1822     S.sent_ESC_br6n = 0;
1823     if (cursor == 0) { /* otherwise it may be bogus */
1824     int col = ((ic >> 32) & 0x7fff) - 1;
1825     if (col > cmdedit_prmt_len) {
1826     cmdedit_x += (col - cmdedit_prmt_len);
1827     while (cmdedit_x >= cmdedit_termw) {
1828     cmdedit_x -= cmdedit_termw;
1829     cmdedit_y++;
1830     }
1831     }
1832     }
1833 niro 1123 continue;
1834 niro 984 }
1835     #endif
1836    
1837 niro 1123 #if ENABLE_UNICODE_SUPPORT
1838     if (unicode_status == UNICODE_ON) {
1839 niro 984 wchar_t wc;
1840    
1841     if ((int32_t)ic < 0) /* KEYCODE_xxx */
1842 niro 1123 break;
1843     // TODO: imagine sequence like: 0xff,<left-arrow>: we are currently losing 0xff...
1844    
1845 niro 984 unicode_buf[unicode_idx++] = ic;
1846     unicode_buf[unicode_idx] = '\0';
1847 niro 1123 if (mbstowcs(&wc, unicode_buf, 1) != 1) {
1848     /* Not (yet?) a valid unicode char */
1849     if (unicode_idx < MB_CUR_MAX) {
1850     timeout = 50;
1851     continue;
1852     }
1853     pushback:
1854     /* Invalid sequence. Save all "bad bytes" except first */
1855     read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1);
1856     # if !ENABLE_UNICODE_PRESERVE_BROKEN
1857     ic = CONFIG_SUBST_WCHAR;
1858     # else
1859     ic = unicode_mark_raw_byte(unicode_buf[0]);
1860     # endif
1861     } else {
1862     /* Valid unicode char, return its code */
1863     ic = wc;
1864 niro 984 }
1865     }
1866     #endif
1867 niro 1123 break;
1868     }
1869 niro 984
1870     return ic;
1871     }
1872    
1873 niro 1123 #if ENABLE_UNICODE_BIDI_SUPPORT
1874     static int isrtl_str(void)
1875     {
1876     int idx = cursor;
1877    
1878     while (idx < command_len && unicode_bidi_is_neutral_wchar(command_ps[idx]))
1879     idx++;
1880     return unicode_bidi_isrtl(command_ps[idx]);
1881     }
1882     #else
1883     # define isrtl_str() 0
1884     #endif
1885    
1886 niro 816 /* leave out the "vi-mode"-only case labels if vi editing isn't
1887     * configured. */
1888 niro 984 #define vi_case(caselabel) IF_FEATURE_EDITING_VI(case caselabel)
1889 niro 816
1890     /* convert uppercase ascii to equivalent control char, for readability */
1891     #undef CTRL
1892     #define CTRL(a) ((a) & ~0x40)
1893    
1894 niro 984 /* maxsize must be >= 2.
1895     * Returns:
1896 niro 816 * -1 on read errors or EOF, or on bare Ctrl-D,
1897     * 0 on ctrl-C (the line entered is still returned in 'command'),
1898     * >0 length of input string, including terminating '\n'
1899     */
1900     int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
1901     {
1902     int len;
1903     #if ENABLE_FEATURE_TAB_COMPLETION
1904     smallint lastWasTab = FALSE;
1905     #endif
1906     smallint break_out = 0;
1907     #if ENABLE_FEATURE_EDITING_VI
1908     smallint vi_cmdmode = 0;
1909     #endif
1910     struct termios initial_settings;
1911     struct termios new_settings;
1912 niro 984 char read_key_buffer[KEYCODE_BUFFER_SIZE];
1913 niro 816
1914     INIT_S();
1915    
1916     if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
1917     || !(initial_settings.c_lflag & ECHO)
1918     ) {
1919     /* Happens when e.g. stty -echo was run before */
1920     parse_and_put_prompt(prompt);
1921 niro 984 /* fflush_all(); - done by parse_and_put_prompt */
1922 niro 816 if (fgets(command, maxsize, stdin) == NULL)
1923     len = -1; /* EOF or error */
1924     else
1925     len = strlen(command);
1926     DEINIT_S();
1927     return len;
1928     }
1929    
1930 niro 984 init_unicode();
1931    
1932 niro 816 // FIXME: audit & improve this
1933     if (maxsize > MAX_LINELEN)
1934     maxsize = MAX_LINELEN;
1935 niro 984 S.maxsize = maxsize;
1936 niro 816
1937     /* With null flags, no other fields are ever used */
1938     state = st ? st : (line_input_t*) &const_int_0;
1939 niro 984 #if MAX_HISTORY > 0
1940     # if ENABLE_FEATURE_EDITING_SAVEHISTORY
1941 niro 816 if ((state->flags & SAVE_HISTORY) && state->hist_file)
1942 niro 984 if (state->cnt_history == 0)
1943     load_history(state);
1944     # endif
1945 niro 816 if (state->flags & DO_HISTORY)
1946     state->cur_history = state->cnt_history;
1947     #endif
1948    
1949     /* prepare before init handlers */
1950     cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
1951     command_len = 0;
1952 niro 1123 #if ENABLE_UNICODE_SUPPORT
1953 niro 984 command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
1954     #else
1955 niro 816 command_ps = command;
1956     command[0] = '\0';
1957 niro 984 #endif
1958     #define command command_must_not_be_used
1959 niro 816
1960     new_settings = initial_settings;
1961     new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1962     /* Turn off echoing and CTRL-C, so we can trap it */
1963     new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
1964     /* Hmm, in linux c_cc[] is not parsed if ICANON is off */
1965     new_settings.c_cc[VMIN] = 1;
1966     new_settings.c_cc[VTIME] = 0;
1967     /* Turn off CTRL-C, so we can trap it */
1968     #ifndef _POSIX_VDISABLE
1969 niro 984 # define _POSIX_VDISABLE '\0'
1970 niro 816 #endif
1971     new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1972     tcsetattr_stdin_TCSANOW(&new_settings);
1973    
1974     /* Now initialize things */
1975     previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
1976     win_changed(0); /* do initial resizing */
1977     #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1978     {
1979     struct passwd *entry;
1980    
1981     entry = getpwuid(geteuid());
1982     if (entry) {
1983     user_buf = xstrdup(entry->pw_name);
1984     home_pwd_buf = xstrdup(entry->pw_dir);
1985     }
1986     }
1987     #endif
1988    
1989     #if 0
1990 niro 984 for (i = 0; i <= MAX_HISTORY; i++)
1991     bb_error_msg("history[%d]:'%s'", i, state->history[i]);
1992 niro 816 bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history);
1993     #endif
1994    
1995 niro 984 /* Print out the command prompt, optionally ask where cursor is */
1996 niro 816 parse_and_put_prompt(prompt);
1997 niro 984 ask_terminal();
1998 niro 816
1999 niro 984 read_key_buffer[0] = 0;
2000 niro 816 while (1) {
2001 niro 984 /*
2002     * The emacs and vi modes share much of the code in the big
2003     * command loop. Commands entered when in vi's command mode
2004     * (aka "escape mode") get an extra bit added to distinguish
2005     * them - this keeps them from being self-inserted. This
2006     * clutters the big switch a bit, but keeps all the code
2007     * in one place.
2008     */
2009     enum {
2010     VI_CMDMODE_BIT = 0x40000000,
2011     /* 0x80000000 bit flags KEYCODE_xxx */
2012     };
2013     int32_t ic, ic_raw;
2014 niro 816
2015 niro 984 fflush_all();
2016     ic = ic_raw = lineedit_read_key(read_key_buffer);
2017 niro 816
2018     #if ENABLE_FEATURE_EDITING_VI
2019     newdelflag = 1;
2020 niro 984 if (vi_cmdmode) {
2021     /* btw, since KEYCODE_xxx are all < 0, this doesn't
2022     * change ic if it contains one of them: */
2023     ic |= VI_CMDMODE_BIT;
2024     }
2025 niro 816 #endif
2026 niro 984
2027 niro 816 switch (ic) {
2028     case '\n':
2029     case '\r':
2030 niro 984 vi_case('\n'|VI_CMDMODE_BIT:)
2031     vi_case('\r'|VI_CMDMODE_BIT:)
2032 niro 816 /* Enter */
2033     goto_new_line();
2034     break_out = 1;
2035     break;
2036     case CTRL('A'):
2037 niro 984 vi_case('0'|VI_CMDMODE_BIT:)
2038 niro 816 /* Control-a -- Beginning of line */
2039     input_backward(cursor);
2040     break;
2041     case CTRL('B'):
2042 niro 984 vi_case('h'|VI_CMDMODE_BIT:)
2043 niro 1123 vi_case('\b'|VI_CMDMODE_BIT:) /* ^H */
2044 niro 984 vi_case('\x7f'|VI_CMDMODE_BIT:) /* DEL */
2045 niro 1123 input_backward(1); /* Move back one character */
2046 niro 816 break;
2047     case CTRL('E'):
2048 niro 984 vi_case('$'|VI_CMDMODE_BIT:)
2049 niro 816 /* Control-e -- End of line */
2050 niro 1123 put_till_end_and_adv_cursor();
2051 niro 816 break;
2052     case CTRL('F'):
2053 niro 984 vi_case('l'|VI_CMDMODE_BIT:)
2054     vi_case(' '|VI_CMDMODE_BIT:)
2055 niro 1123 input_forward(); /* Move forward one character */
2056 niro 816 break;
2057 niro 1123 case '\b': /* ^H */
2058 niro 816 case '\x7f': /* DEL */
2059 niro 1123 if (!isrtl_str())
2060     input_backspace();
2061     else
2062     input_delete(0);
2063 niro 816 break;
2064 niro 1123 case KEYCODE_DELETE:
2065     if (!isrtl_str())
2066     input_delete(0);
2067     else
2068     input_backspace();
2069     break;
2070 niro 816 #if ENABLE_FEATURE_TAB_COMPLETION
2071     case '\t':
2072     input_tab(&lastWasTab);
2073     break;
2074     #endif
2075     case CTRL('K'):
2076     /* Control-k -- clear to end of line */
2077 niro 984 command_ps[cursor] = BB_NUL;
2078 niro 816 command_len = cursor;
2079 niro 1123 printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
2080 niro 816 break;
2081     case CTRL('L'):
2082 niro 984 vi_case(CTRL('L')|VI_CMDMODE_BIT:)
2083 niro 816 /* Control-l -- clear screen */
2084 niro 1123 printf("\033[H"); /* cursor to top,left */
2085 niro 816 redraw(0, command_len - cursor);
2086     break;
2087     #if MAX_HISTORY > 0
2088     case CTRL('N'):
2089 niro 984 vi_case(CTRL('N')|VI_CMDMODE_BIT:)
2090     vi_case('j'|VI_CMDMODE_BIT:)
2091 niro 816 /* Control-n -- Get next command in history */
2092     if (get_next_history())
2093     goto rewrite_line;
2094     break;
2095     case CTRL('P'):
2096 niro 984 vi_case(CTRL('P')|VI_CMDMODE_BIT:)
2097     vi_case('k'|VI_CMDMODE_BIT:)
2098 niro 816 /* Control-p -- Get previous command from history */
2099     if (get_previous_history())
2100     goto rewrite_line;
2101     break;
2102     #endif
2103     case CTRL('U'):
2104 niro 984 vi_case(CTRL('U')|VI_CMDMODE_BIT:)
2105 niro 816 /* Control-U -- Clear line before cursor */
2106     if (cursor) {
2107     command_len -= cursor;
2108 niro 984 memmove(command_ps, command_ps + cursor,
2109     (command_len + 1) * sizeof(command_ps[0]));
2110 niro 816 redraw(cmdedit_y, command_len);
2111     }
2112     break;
2113     case CTRL('W'):
2114 niro 984 vi_case(CTRL('W')|VI_CMDMODE_BIT:)
2115 niro 816 /* Control-W -- Remove the last word */
2116 niro 984 while (cursor > 0 && BB_isspace(command_ps[cursor-1]))
2117 niro 816 input_backspace();
2118 niro 984 while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
2119 niro 816 input_backspace();
2120     break;
2121    
2122     #if ENABLE_FEATURE_EDITING_VI
2123 niro 984 case 'i'|VI_CMDMODE_BIT:
2124 niro 816 vi_cmdmode = 0;
2125     break;
2126 niro 984 case 'I'|VI_CMDMODE_BIT:
2127 niro 816 input_backward(cursor);
2128     vi_cmdmode = 0;
2129     break;
2130 niro 984 case 'a'|VI_CMDMODE_BIT:
2131 niro 816 input_forward();
2132     vi_cmdmode = 0;
2133     break;
2134 niro 984 case 'A'|VI_CMDMODE_BIT:
2135 niro 1123 put_till_end_and_adv_cursor();
2136 niro 816 vi_cmdmode = 0;
2137     break;
2138 niro 984 case 'x'|VI_CMDMODE_BIT:
2139 niro 816 input_delete(1);
2140     break;
2141 niro 984 case 'X'|VI_CMDMODE_BIT:
2142 niro 816 if (cursor > 0) {
2143     input_backward(1);
2144     input_delete(1);
2145     }
2146     break;
2147 niro 984 case 'W'|VI_CMDMODE_BIT:
2148     vi_Word_motion(1);
2149 niro 816 break;
2150 niro 984 case 'w'|VI_CMDMODE_BIT:
2151     vi_word_motion(1);
2152 niro 816 break;
2153 niro 984 case 'E'|VI_CMDMODE_BIT:
2154     vi_End_motion();
2155 niro 816 break;
2156 niro 984 case 'e'|VI_CMDMODE_BIT:
2157     vi_end_motion();
2158 niro 816 break;
2159 niro 984 case 'B'|VI_CMDMODE_BIT:
2160     vi_Back_motion();
2161 niro 816 break;
2162 niro 984 case 'b'|VI_CMDMODE_BIT:
2163     vi_back_motion();
2164 niro 816 break;
2165 niro 984 case 'C'|VI_CMDMODE_BIT:
2166 niro 816 vi_cmdmode = 0;
2167     /* fall through */
2168 niro 984 case 'D'|VI_CMDMODE_BIT:
2169 niro 816 goto clear_to_eol;
2170    
2171 niro 984 case 'c'|VI_CMDMODE_BIT:
2172 niro 816 vi_cmdmode = 0;
2173     /* fall through */
2174 niro 984 case 'd'|VI_CMDMODE_BIT: {
2175 niro 816 int nc, sc;
2176 niro 984
2177     ic = lineedit_read_key(read_key_buffer);
2178     if (errno) /* error */
2179 niro 816 goto prepare_to_die;
2180 niro 984 if (ic == ic_raw) { /* "cc", "dd" */
2181 niro 816 input_backward(cursor);
2182     goto clear_to_eol;
2183     break;
2184     }
2185 niro 984
2186     sc = cursor;
2187     switch (ic) {
2188 niro 816 case 'w':
2189     case 'W':
2190     case 'e':
2191     case 'E':
2192 niro 984 switch (ic) {
2193 niro 816 case 'w': /* "dw", "cw" */
2194 niro 984 vi_word_motion(vi_cmdmode);
2195 niro 816 break;
2196     case 'W': /* 'dW', 'cW' */
2197 niro 984 vi_Word_motion(vi_cmdmode);
2198 niro 816 break;
2199     case 'e': /* 'de', 'ce' */
2200 niro 984 vi_end_motion();
2201 niro 816 input_forward();
2202     break;
2203     case 'E': /* 'dE', 'cE' */
2204 niro 984 vi_End_motion();
2205 niro 816 input_forward();
2206     break;
2207     }
2208     nc = cursor;
2209     input_backward(cursor - sc);
2210     while (nc-- > cursor)
2211     input_delete(1);
2212     break;
2213     case 'b': /* "db", "cb" */
2214     case 'B': /* implemented as B */
2215 niro 984 if (ic == 'b')
2216     vi_back_motion();
2217 niro 816 else
2218 niro 984 vi_Back_motion();
2219 niro 816 while (sc-- > cursor)
2220     input_delete(1);
2221     break;
2222     case ' ': /* "d ", "c " */
2223     input_delete(1);
2224     break;
2225     case '$': /* "d$", "c$" */
2226 niro 984 clear_to_eol:
2227 niro 816 while (cursor < command_len)
2228     input_delete(1);
2229     break;
2230     }
2231     break;
2232     }
2233 niro 984 case 'p'|VI_CMDMODE_BIT:
2234 niro 816 input_forward();
2235     /* fallthrough */
2236 niro 984 case 'P'|VI_CMDMODE_BIT:
2237 niro 816 put();
2238     break;
2239 niro 984 case 'r'|VI_CMDMODE_BIT:
2240     //FIXME: unicode case?
2241     ic = lineedit_read_key(read_key_buffer);
2242     if (errno) /* error */
2243 niro 816 goto prepare_to_die;
2244 niro 984 if (ic < ' ' || ic > 255) {
2245 niro 816 beep();
2246 niro 984 } else {
2247     command_ps[cursor] = ic;
2248     bb_putchar(ic);
2249 niro 816 bb_putchar('\b');
2250     }
2251     break;
2252     case '\x1b': /* ESC */
2253     if (state->flags & VI_MODE) {
2254 niro 984 /* insert mode --> command mode */
2255 niro 816 vi_cmdmode = 1;
2256     input_backward(1);
2257     }
2258 niro 984 break;
2259     #endif /* FEATURE_COMMAND_EDITING_VI */
2260 niro 816
2261     #if MAX_HISTORY > 0
2262 niro 984 case KEYCODE_UP:
2263     if (get_previous_history())
2264     goto rewrite_line;
2265     beep();
2266     break;
2267     case KEYCODE_DOWN:
2268     if (!get_next_history())
2269 niro 816 break;
2270     rewrite_line:
2271 niro 984 /* Rewrite the line with the selected history item */
2272     /* change command */
2273     command_len = load_string(state->history[state->cur_history] ?
2274     state->history[state->cur_history] : "", maxsize);
2275     /* redraw and go to eol (bol, in vi) */
2276     redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
2277     break;
2278 niro 816 #endif
2279 niro 984 case KEYCODE_RIGHT:
2280     input_forward();
2281     break;
2282     case KEYCODE_LEFT:
2283     input_backward(1);
2284     break;
2285     case KEYCODE_CTRL_LEFT:
2286     ctrl_left();
2287     break;
2288     case KEYCODE_CTRL_RIGHT:
2289     ctrl_right();
2290     break;
2291     case KEYCODE_HOME:
2292     input_backward(cursor);
2293     break;
2294     case KEYCODE_END:
2295 niro 1123 put_till_end_and_adv_cursor();
2296 niro 984 break;
2297    
2298     default:
2299     if (initial_settings.c_cc[VINTR] != 0
2300     && ic_raw == initial_settings.c_cc[VINTR]
2301     ) {
2302     /* Ctrl-C (usually) - stop gathering input */
2303     goto_new_line();
2304     command_len = 0;
2305     break_out = -1; /* "do not append '\n'" */
2306 niro 816 break;
2307     }
2308 niro 984 if (initial_settings.c_cc[VEOF] != 0
2309     && ic_raw == initial_settings.c_cc[VEOF]
2310     ) {
2311     /* Ctrl-D (usually) - delete one character,
2312     * or exit if len=0 and no chars to delete */
2313     if (command_len == 0) {
2314     errno = 0;
2315 niro 1179
2316     case -1: /* error (e.g. EIO when tty is destroyed) */
2317 niro 984 #if ENABLE_FEATURE_EDITING_VI
2318     prepare_to_die:
2319     #endif
2320     break_out = command_len = -1;
2321 niro 816 break;
2322     }
2323 niro 984 input_delete(0);
2324     break;
2325 niro 816 }
2326 niro 984 // /* Control-V -- force insert of next char */
2327     // if (c == CTRL('V')) {
2328     // if (safe_read(STDIN_FILENO, &c, 1) < 1)
2329     // goto prepare_to_die;
2330     // if (c == 0) {
2331     // beep();
2332     // break;
2333     // }
2334     // }
2335     if (ic < ' '
2336 niro 1123 || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
2337     || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
2338 niro 984 ) {
2339     /* If VI_CMDMODE_BIT is set, ic is >= 256
2340     * and vi mode ignores unexpected chars.
2341     * Otherwise, we are here if ic is a
2342     * control char or an unhandled ESC sequence,
2343     * which is also ignored.
2344     */
2345 niro 816 break;
2346 niro 984 }
2347     if ((int)command_len >= (maxsize - 2)) {
2348     /* Not enough space for the char and EOL */
2349 niro 816 break;
2350 niro 984 }
2351 niro 816
2352     command_len++;
2353 niro 984 if (cursor == (command_len - 1)) {
2354     /* We are at the end, append */
2355     command_ps[cursor] = ic;
2356     command_ps[cursor + 1] = BB_NUL;
2357 niro 1123 put_cur_glyph_and_inc_cursor();
2358     if (unicode_bidi_isrtl(ic))
2359     input_backward(1);
2360 niro 984 } else {
2361     /* In the middle, insert */
2362 niro 816 int sc = cursor;
2363    
2364 niro 984 memmove(command_ps + sc + 1, command_ps + sc,
2365     (command_len - sc) * sizeof(command_ps[0]));
2366     command_ps[sc] = ic;
2367 niro 1123 /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
2368     if (!isrtl_str())
2369     sc++; /* no */
2370     put_till_end_and_adv_cursor();
2371 niro 816 /* to prev x pos + 1 */
2372     input_backward(cursor - sc);
2373     }
2374     break;
2375 niro 984 } /* switch (ic) */
2376    
2377     if (break_out)
2378 niro 816 break;
2379    
2380     #if ENABLE_FEATURE_TAB_COMPLETION
2381 niro 984 if (ic_raw != '\t')
2382 niro 816 lastWasTab = FALSE;
2383     #endif
2384 niro 984 } /* while (1) */
2385    
2386     #if ENABLE_FEATURE_EDITING_ASK_TERMINAL
2387     if (S.sent_ESC_br6n) {
2388     /* "sleep 1; busybox ash" + hold [Enter] to trigger.
2389     * We sent "ESC [ 6 n", but got '\n' first, and
2390     * KEYCODE_CURSOR_POS response is now buffered from terminal.
2391     * It's bad already and not much can be done with it
2392     * (it _will_ be visible for the next process to read stdin),
2393     * but without this delay it even shows up on the screen
2394     * as garbage because we restore echo settings with tcsetattr
2395     * before it comes in. UGLY!
2396     */
2397     usleep(20*1000);
2398 niro 816 }
2399 niro 984 #endif
2400 niro 816
2401 niro 984 /* Stop bug catching using "command_must_not_be_used" trick */
2402     #undef command
2403    
2404 niro 1123 #if ENABLE_UNICODE_SUPPORT
2405 niro 984 command[0] = '\0';
2406 niro 816 if (command_len > 0)
2407 niro 984 command_len = save_string(command, maxsize - 1);
2408     free(command_ps);
2409     #endif
2410    
2411     if (command_len > 0)
2412 niro 816 remember_in_history(command);
2413    
2414     if (break_out > 0) {
2415     command[command_len++] = '\n';
2416     command[command_len] = '\0';
2417     }
2418    
2419     #if ENABLE_FEATURE_TAB_COMPLETION
2420     free_tab_completion_data();
2421     #endif
2422    
2423     /* restore initial_settings */
2424     tcsetattr_stdin_TCSANOW(&initial_settings);
2425     /* restore SIGWINCH handler */
2426     signal(SIGWINCH, previous_SIGWINCH_handler);
2427 niro 984 fflush_all();
2428 niro 816
2429     len = command_len;
2430     DEINIT_S();
2431    
2432     return len; /* can't return command_len, DEINIT_S() destroys it */
2433     }
2434    
2435     #else
2436    
2437     #undef read_line_input
2438     int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
2439     {
2440     fputs(prompt, stdout);
2441 niro 984 fflush_all();
2442 niro 816 fgets(command, maxsize, stdin);
2443     return strlen(command);
2444     }
2445    
2446 niro 984 #endif /* FEATURE_EDITING */
2447 niro 816
2448    
2449     /*
2450     * Testing
2451     */
2452    
2453     #ifdef TEST
2454    
2455     #include <locale.h>
2456    
2457     const char *applet_name = "debug stuff usage";
2458    
2459     int main(int argc, char **argv)
2460     {
2461     char buff[MAX_LINELEN];
2462     char *prompt =
2463     #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2464     "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
2465     "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
2466     "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
2467     #else
2468     "% ";
2469     #endif
2470    
2471     while (1) {
2472     int l;
2473     l = read_line_input(prompt, buff);
2474     if (l <= 0 || buff[l-1] != '\n')
2475     break;
2476     buff[l-1] = 0;
2477     printf("*** read_line_input() returned line =%s=\n", buff);
2478     }
2479     printf("*** read_line_input() detect ^D\n");
2480     return 0;
2481     }
2482    
2483     #endif /* TEST */