blob: 68772fe0551edce7b4fd19373fa2fe5262917f2c [file] [log] [blame]
Erik Andersenc7c634b2000-03-19 05:28:55 +00001/* vi: set sw=4 ts=4: */
Erik Andersen13456d12000-03-16 08:09:57 +00002/*
Eric Andersenaff114c2004-04-14 17:51:38 +00003 * Termios command line History and Editing.
Erik Andersen13456d12000-03-16 08:09:57 +00004 *
Eric Andersen81fe1232003-07-29 06:38:40 +00005 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
Eric Andersen7467c8d2001-07-12 20:26:32 +00006 * Written by: Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersen5f2c79d2001-02-16 18:36:04 +00007 *
8 * Used ideas:
9 * Adam Rogoyski <rogoyski@cs.utexas.edu>
10 * Dave Cinege <dcinege@psychosis.com>
11 * Jakub Jelinek (c) 1995
Eric Andersen81fe1232003-07-29 06:38:40 +000012 * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
Eric Andersen5f2c79d2001-02-16 18:36:04 +000013 *
Erik Andersen13456d12000-03-16 08:09:57 +000014 * This code is 'as is' with no warranty.
Erik Andersen13456d12000-03-16 08:09:57 +000015 */
16
17/*
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000018 Usage and known bugs:
Erik Andersen13456d12000-03-16 08:09:57 +000019 Terminal key codes are not extensive, and more will probably
20 need to be added. This version was created on Debian GNU/Linux 2.x.
21 Delete, Backspace, Home, End, and the arrow keys were tested
22 to work in an Xterm and console. Ctrl-A also works as Home.
Mark Whitley4e338752001-01-26 20:42:23 +000023 Ctrl-E also works as End.
Erik Andersen13456d12000-03-16 08:09:57 +000024
Eric Andersen5f2c79d2001-02-16 18:36:04 +000025 Small bugs (simple effect):
26 - not true viewing if terminal size (x*y symbols) less
27 size (prompt + editor`s line + 2 symbols)
Eric Andersenb3d6e2d2001-03-13 22:57:56 +000028 - not true viewing if length prompt less terminal width
Erik Andersen13456d12000-03-16 08:09:57 +000029 */
30
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000031#include "busybox.h"
Eric Andersencbe31da2001-02-20 06:14:08 +000032#include <sys/ioctl.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000033
"Robert P. J. Day"4eddb422006-07-03 00:46:47 +000034#include "cmdedit.h"
Glenn L McGrath67285962004-01-14 09:34:51 +000035
Glenn L McGrath475820c2004-01-22 12:42:23 +000036
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000037#if ENABLE_LOCALE_SUPPORT
38#define Isprint(c) isprint(c)
Eric Andersene5dfced2001-04-09 22:48:12 +000039#else
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000040#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
Eric Andersene5dfced2001-04-09 22:48:12 +000041#endif
42
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000043
44/* FIXME: obsolete CONFIG item? */
45#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
46
47
Glenn L McGrath3b251852004-01-03 12:07:32 +000048#ifdef TEST
Eric Andersen5f2c79d2001-02-16 18:36:04 +000049
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000050#define ENABLE_FEATURE_COMMAND_EDITING 0
51#define ENABLE_FEATURE_COMMAND_TAB_COMPLETION 0
52#define ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 0
53#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
54#define ENABLE_FEATURE_CLEAN_UP 0
Eric Andersen5f2c79d2001-02-16 18:36:04 +000055
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +000056#endif /* TEST */
Eric Andersen5f2c79d2001-02-16 18:36:04 +000057
Eric Andersen5165fbe2001-02-20 06:42:29 +000058
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000059#if ENABLE_FEATURE_COMMAND_EDITING
Erik Andersen13456d12000-03-16 08:09:57 +000060
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000061#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT
62#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR 1
Eric Andersen5f2c79d2001-02-16 18:36:04 +000063#endif
64
Eric Andersen5f2c79d2001-02-16 18:36:04 +000065/* Maximum length of the linked list for the command line history */
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000066#if !ENABLE_FEATURE_COMMAND_HISTORY
Robert Griebl350d26b2002-12-03 22:45:46 +000067#define MAX_HISTORY 15
68#else
Denis Vlasenko9d4533e2006-11-02 22:09:37 +000069#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
Robert Griebl350d26b2002-12-03 22:45:46 +000070#endif
71
Denis Vlasenko9d4533e2006-11-02 22:09:37 +000072#if MAX_HISTORY > 0
Glenn L McGrath062c74f2002-11-27 09:29:49 +000073static char *history[MAX_HISTORY+1]; /* history + current */
74/* saved history lines */
75static int n_history;
76/* current pointer to history line */
77static int cur_history;
78#endif
Erik Andersen1d1d9502000-04-21 01:26:49 +000079
Denis Vlasenko7f1dc212006-12-19 01:10:25 +000080//#include <termios.h>
Denis Vlasenko0a8a7742006-12-21 22:27:10 +000081#define setTermSettings(fd,argp) tcsetattr(fd, TCSANOW, argp)
Glenn L McGrath78b0e372001-06-26 02:06:08 +000082#define getTermSettings(fd,argp) tcgetattr(fd, argp);
Erik Andersen1d1d9502000-04-21 01:26:49 +000083
84/* Current termio and the previous termio before starting sh */
Eric Andersen63a86222000-11-07 06:52:13 +000085static struct termios initial_settings, new_settings;
Erik Andersen8ea7d8c2000-05-20 00:40:08 +000086
87
Mark Whitley4e338752001-01-26 20:42:23 +000088static
Eric Andersenc470f442003-07-28 09:56:35 +000089volatile int cmdedit_termw = 80; /* actual terminal width */
Mark Whitley4e338752001-01-26 20:42:23 +000090static
Eric Andersenc470f442003-07-28 09:56:35 +000091volatile int handlers_sets = 0; /* Set next bites: */
Eric Andersen5f2c79d2001-02-16 18:36:04 +000092
Mark Whitley4e338752001-01-26 20:42:23 +000093enum {
Eric Andersenc470f442003-07-28 09:56:35 +000094 SET_ATEXIT = 1, /* when atexit() has been called
Eric Andersenb3d6e2d2001-03-13 22:57:56 +000095 and get euid,uid,gid to fast compare */
Eric Andersen7467c8d2001-07-12 20:26:32 +000096 SET_WCHG_HANDLERS = 2, /* winchg signal handler */
97 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */
Mark Whitley4e338752001-01-26 20:42:23 +000098};
Erik Andersen13456d12000-03-16 08:09:57 +000099
Mark Whitley4e338752001-01-26 20:42:23 +0000100
Eric Andersenc470f442003-07-28 09:56:35 +0000101static int cmdedit_x; /* real x terminal position */
102static int cmdedit_y; /* pseudoreal y terminal position */
103static int cmdedit_prmt_len; /* lenght prompt without colores string */
Eric Andersen86349772000-12-18 20:25:50 +0000104
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000105static int cursor; /* required globals for signal handler */
106static int len; /* --- "" - - "" -- -"- --""-- --""--- */
107static char *command_ps; /* --- "" - - "" -- -"- --""-- --""--- */
108static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; /* -- */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000109
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000110#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000111static char *user_buf = "";
112static char *home_pwd_buf = "";
113static int my_euid;
114#endif
115
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000116#if ENABLE_FEATURE_SH_FANCY_PROMPT
Glenn L McGrath062c74f2002-11-27 09:29:49 +0000117static char *hostname_buf;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000118static int num_ok_lines = 1;
119#endif
120
121
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000122#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000123
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000124#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000125static int my_euid;
126#endif
127
128static int my_uid;
129static int my_gid;
130
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000131#endif /* FEATURE_COMMAND_TAB_COMPLETION */
Eric Andersenc470f442003-07-28 09:56:35 +0000132
Mark Whitley4e338752001-01-26 20:42:23 +0000133static void cmdedit_setwidth(int w, int redraw_flg);
Erik Andersen13456d12000-03-16 08:09:57 +0000134
Mark Whitley4e338752001-01-26 20:42:23 +0000135static void win_changed(int nsig)
Eric Andersenb3dc3b82001-01-04 11:08:45 +0000136{
Eric Andersenc470f442003-07-28 09:56:35 +0000137 static sighandler_t previous_SIGWINCH_handler; /* for reset */
Erik Andersen61677fe2000-04-13 01:18:56 +0000138
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000139 /* emulate || signal call */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000140 if (nsig == -SIGWINCH || nsig == SIGWINCH) {
Eric Andersen8efe9672003-09-15 08:33:45 +0000141 int width = 0;
142 get_terminal_width_height(0, &width, NULL);
143 cmdedit_setwidth(width, nsig == SIGWINCH);
Mark Whitley4e338752001-01-26 20:42:23 +0000144 }
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000145 /* Unix not all standard in recall signal */
Mark Whitley4e338752001-01-26 20:42:23 +0000146
Eric Andersenc470f442003-07-28 09:56:35 +0000147 if (nsig == -SIGWINCH) /* save previous handler */
Mark Whitley4e338752001-01-26 20:42:23 +0000148 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
Eric Andersenc470f442003-07-28 09:56:35 +0000149 else if (nsig == SIGWINCH) /* signaled called handler */
150 signal(SIGWINCH, win_changed); /* set for next call */
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000151 else /* nsig == 0 */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000152 /* set previous handler */
Eric Andersenc470f442003-07-28 09:56:35 +0000153 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */
Mark Whitley4e338752001-01-26 20:42:23 +0000154}
Eric Andersenb3dc3b82001-01-04 11:08:45 +0000155
156static void cmdedit_reset_term(void)
Erik Andersen13456d12000-03-16 08:09:57 +0000157{
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000158 if (handlers_sets & SET_RESET_TERM) {
Eric Andersene5dfced2001-04-09 22:48:12 +0000159/* sparc and other have broken termios support: use old termio handling. */
Eric Andersen70060d22004-03-27 10:02:48 +0000160 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
Mark Whitley4e338752001-01-26 20:42:23 +0000161 handlers_sets &= ~SET_RESET_TERM;
162 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000163 if (handlers_sets & SET_WCHG_HANDLERS) {
Mark Whitley4e338752001-01-26 20:42:23 +0000164 /* reset SIGWINCH handler to previous (default) */
165 win_changed(0);
166 handlers_sets &= ~SET_WCHG_HANDLERS;
167 }
168 fflush(stdout);
Erik Andersen13456d12000-03-16 08:09:57 +0000169}
170
Mark Whitley4e338752001-01-26 20:42:23 +0000171
Mark Whitley4e338752001-01-26 20:42:23 +0000172/* special for recount position for scroll and remove terminal margin effect */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000173static void cmdedit_set_out_char(int next_char)
174{
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000175 int c = (unsigned char)command_ps[cursor];
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000176
177 if (c == 0)
Eric Andersenc470f442003-07-28 09:56:35 +0000178 c = ' '; /* destroy end char? */
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000179#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersenc470f442003-07-28 09:56:35 +0000180 if (!Isprint(c)) { /* Inverse put non-printable characters */
Eric Andersenf9ff8a72001-03-15 20:51:09 +0000181 if (c >= 128)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000182 c -= 128;
Eric Andersenf9ff8a72001-03-15 20:51:09 +0000183 if (c < ' ')
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000184 c += '@';
185 if (c == 127)
186 c = '?';
187 printf("\033[7m%c\033[0m", c);
188 } else
189#endif
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000190 {
191 if (initial_settings.c_lflag & ECHO)
192 putchar(c);
193 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000194 if (++cmdedit_x >= cmdedit_termw) {
Mark Whitley4e338752001-01-26 20:42:23 +0000195 /* terminal is scrolled down */
196 cmdedit_y++;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000197 cmdedit_x = 0;
Mark Whitley4e338752001-01-26 20:42:23 +0000198
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000199 if (!next_char)
Mark Whitley4e338752001-01-26 20:42:23 +0000200 next_char = ' ';
201 /* destroy "(auto)margin" */
202 putchar(next_char);
203 putchar('\b');
204 }
205 cursor++;
Erik Andersen13456d12000-03-16 08:09:57 +0000206}
207
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000208/* Move to end line. Bonus: rewrite line from cursor */
209static void input_end(void)
210{
211 while (cursor < len)
212 cmdedit_set_out_char(0);
Mark Whitley4e338752001-01-26 20:42:23 +0000213}
214
215/* Go to the next line */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000216static void goto_new_line(void)
217{
Mark Whitley4e338752001-01-26 20:42:23 +0000218 input_end();
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000219 if (cmdedit_x)
220 putchar('\n');
Mark Whitley4e338752001-01-26 20:42:23 +0000221}
222
223
Rob Landley88621d72006-08-29 19:41:06 +0000224static void out1str(const char *s)
Erik Andersenf0657d32000-04-12 17:49:52 +0000225{
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000226 if (s)
Robert Grieblb2301592002-07-30 23:13:51 +0000227 fputs(s, stdout);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000228}
Eric Andersen81fe1232003-07-29 06:38:40 +0000229
Rob Landley88621d72006-08-29 19:41:06 +0000230static void beep(void)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000231{
232 putchar('\007');
Erik Andersen13456d12000-03-16 08:09:57 +0000233}
234
Eric Andersenaff114c2004-04-14 17:51:38 +0000235/* Move back one character */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000236/* special for slow terminal */
237static void input_backward(int num)
238{
239 if (num > cursor)
240 num = cursor;
Eric Andersenc470f442003-07-28 09:56:35 +0000241 cursor -= num; /* new cursor (in command, not terminal) */
Erik Andersen13456d12000-03-16 08:09:57 +0000242
Eric Andersenc470f442003-07-28 09:56:35 +0000243 if (cmdedit_x >= num) { /* no to up line */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000244 cmdedit_x -= num;
245 if (num < 4)
246 while (num-- > 0)
247 putchar('\b');
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000248 else
249 printf("\033[%dD", num);
250 } else {
251 int count_y;
252
253 if (cmdedit_x) {
Eric Andersenc470f442003-07-28 09:56:35 +0000254 putchar('\r'); /* back to first terminal pos. */
255 num -= cmdedit_x; /* set previous backward */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000256 }
257 count_y = 1 + num / cmdedit_termw;
258 printf("\033[%dA", count_y);
259 cmdedit_y -= count_y;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000260 /* require forward after uping */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000261 cmdedit_x = cmdedit_termw * count_y - num;
Eric Andersenc470f442003-07-28 09:56:35 +0000262 printf("\033[%dC", cmdedit_x); /* set term cursor */
Erik Andersen13456d12000-03-16 08:09:57 +0000263 }
Erik Andersen13456d12000-03-16 08:09:57 +0000264}
265
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000266static void put_prompt(void)
267{
268 out1str(cmdedit_prompt);
Eric Andersenc470f442003-07-28 09:56:35 +0000269 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000270 cursor = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000271 cmdedit_y = 0; /* new quasireal y */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000272}
273
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000274#if !ENABLE_FEATURE_SH_FANCY_PROMPT
Eric Andersenb3d6e2d2001-03-13 22:57:56 +0000275static void parse_prompt(const char *prmt_ptr)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000276{
Eric Andersenb3d6e2d2001-03-13 22:57:56 +0000277 cmdedit_prompt = prmt_ptr;
278 cmdedit_prmt_len = strlen(prmt_ptr);
279 put_prompt();
280}
281#else
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000282static void parse_prompt(const char *prmt_ptr)
283{
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000284 int prmt_len = 0;
"Vladimir N. Oleynik"f0874802005-09-05 15:46:26 +0000285 size_t cur_prmt_len = 0;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000286 char flg_not_length = '[';
Rob Landley081e3842006-08-03 20:07:35 +0000287 char *prmt_mem_ptr = xzalloc(1);
Eric Andersene5dfced2001-04-09 22:48:12 +0000288 char *pwd_buf = xgetcwd(0);
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000289 char buf2[PATH_MAX + 1];
290 char buf[2];
291 char c;
Eric Andersene5dfced2001-04-09 22:48:12 +0000292 char *pbuf;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000293
Eric Andersen5f265b72001-05-11 16:58:46 +0000294 if (!pwd_buf) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000295 pwd_buf = (char *)bb_msg_unknown;
Eric Andersen5f265b72001-05-11 16:58:46 +0000296 }
297
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000298 while (*prmt_ptr) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000299 pbuf = buf;
Eric Andersene5dfced2001-04-09 22:48:12 +0000300 pbuf[1] = 0;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000301 c = *prmt_ptr++;
302 if (c == '\\') {
Eric Andersene5dfced2001-04-09 22:48:12 +0000303 const char *cp = prmt_ptr;
304 int l;
Eric Andersenc470f442003-07-28 09:56:35 +0000305
Manuel Novoa III cad53642003-03-19 09:13:01 +0000306 c = bb_process_escape_sequence(&prmt_ptr);
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000307 if (prmt_ptr == cp) {
308 if (*cp == 0)
309 break;
310 c = *prmt_ptr++;
311 switch (c) {
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000312#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000313 case 'u':
314 pbuf = user_buf;
315 break;
Eric Andersenc470f442003-07-28 09:56:35 +0000316#endif
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000317 case 'h':
318 pbuf = hostname_buf;
319 if (pbuf == 0) {
320 pbuf = xzalloc(256);
321 if (gethostname(pbuf, 255) < 0) {
322 strcpy(pbuf, "?");
323 } else {
324 char *s = strchr(pbuf, '.');
325 if (s)
326 *s = 0;
327 }
328 hostname_buf = pbuf;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000329 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000330 break;
331 case '$':
332 c = (my_euid == 0 ? '#' : '$');
333 break;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000334#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000335 case 'w':
336 pbuf = pwd_buf;
337 l = strlen(home_pwd_buf);
338 if (home_pwd_buf[0] != 0
339 && strncmp(home_pwd_buf, pbuf, l) == 0
340 && (pbuf[l]=='/' || pbuf[l]=='\0')
341 && strlen(pwd_buf+l)<PATH_MAX
342 ) {
343 pbuf = buf2;
344 *pbuf = '~';
345 strcpy(pbuf+1, pwd_buf+l);
346 }
347 break;
Eric Andersenc470f442003-07-28 09:56:35 +0000348#endif
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000349 case 'W':
350 pbuf = pwd_buf;
351 cp = strrchr(pbuf,'/');
352 if (cp != NULL && cp != pbuf)
353 pbuf += (cp-pbuf) + 1;
354 break;
355 case '!':
356 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
357 break;
358 case 'e': case 'E': /* \e \E = \033 */
359 c = '\033';
360 break;
361 case 'x': case 'X':
362 for (l = 0; l < 3;) {
363 int h;
364 buf2[l++] = *prmt_ptr;
365 buf2[l] = 0;
366 h = strtol(buf2, &pbuf, 16);
367 if (h > UCHAR_MAX || (pbuf - buf2) < l) {
368 l--;
369 break;
370 }
371 prmt_ptr++;
372 }
Eric Andersene5dfced2001-04-09 22:48:12 +0000373 buf2[l] = 0;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000374 c = (char)strtol(buf2, 0, 16);
375 if (c == 0)
376 c = '?';
377 pbuf = buf;
378 break;
379 case '[': case ']':
380 if (c == flg_not_length) {
381 flg_not_length = flg_not_length == '[' ? ']' : '[';
382 continue;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000383 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000384 break;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000385 }
Eric Andersenc470f442003-07-28 09:56:35 +0000386 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000387 }
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000388 if (pbuf == buf)
Eric Andersene5dfced2001-04-09 22:48:12 +0000389 *pbuf = c;
"Vladimir N. Oleynik"f0874802005-09-05 15:46:26 +0000390 cur_prmt_len = strlen(pbuf);
391 prmt_len += cur_prmt_len;
392 if (flg_not_length != ']')
393 cmdedit_prmt_len += cur_prmt_len;
Eric Andersene5dfced2001-04-09 22:48:12 +0000394 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000395 }
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000396 if (pwd_buf!=(char *)bb_msg_unknown)
Eric Andersen8f697842001-07-02 15:36:57 +0000397 free(pwd_buf);
Eric Andersenb3d6e2d2001-03-13 22:57:56 +0000398 cmdedit_prompt = prmt_mem_ptr;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000399 put_prompt();
400}
Eric Andersenb3d6e2d2001-03-13 22:57:56 +0000401#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000402
403
Eric Andersenaff114c2004-04-14 17:51:38 +0000404/* draw prompt, editor line, and clear tail */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000405static void redraw(int y, int back_cursor)
406{
Eric Andersenc470f442003-07-28 09:56:35 +0000407 if (y > 0) /* up to start y */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000408 printf("\033[%dA", y);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000409 putchar('\r');
410 put_prompt();
Eric Andersenc470f442003-07-28 09:56:35 +0000411 input_end(); /* rewrite */
412 printf("\033[J"); /* destroy tail after cursor */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000413 input_backward(back_cursor);
414}
415
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000416#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox0f2dd9f2006-03-07 20:26:11 +0000417#define DELBUFSIZ 128
418static char *delbuf; /* a (malloced) place to store deleted characters */
419static char *delp;
420static char newdelflag; /* whether delbuf should be reused yet */
Paul Fox3f11b1b2005-08-04 19:04:46 +0000421#endif
422
423/* Delete the char in front of the cursor, optionally saving it
424 * for later putback */
425static void input_delete(int save)
Erik Andersenf0657d32000-04-12 17:49:52 +0000426{
Mark Whitley4e338752001-01-26 20:42:23 +0000427 int j = cursor;
Erik Andersena2685732000-04-09 18:27:46 +0000428
Mark Whitley4e338752001-01-26 20:42:23 +0000429 if (j == len)
Erik Andersenf0657d32000-04-12 17:49:52 +0000430 return;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000431
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000432#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +0000433 if (save) {
434 if (newdelflag) {
Paul Fox0f2dd9f2006-03-07 20:26:11 +0000435 if (!delbuf)
436 delbuf = malloc(DELBUFSIZ);
437 /* safe if malloc fails */
Paul Fox3f11b1b2005-08-04 19:04:46 +0000438 delp = delbuf;
439 newdelflag = 0;
440 }
Paul Fox0f2dd9f2006-03-07 20:26:11 +0000441 if (delbuf && (delp - delbuf < DELBUFSIZ))
Paul Fox3f11b1b2005-08-04 19:04:46 +0000442 *delp++ = command_ps[j];
443 }
444#endif
445
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000446 strcpy(command_ps + j, command_ps + j + 1);
Mark Whitley4e338752001-01-26 20:42:23 +0000447 len--;
Paul Fox3f11b1b2005-08-04 19:04:46 +0000448 input_end(); /* rewrite new line */
Eric Andersenc470f442003-07-28 09:56:35 +0000449 cmdedit_set_out_char(0); /* destroy end char */
450 input_backward(cursor - j); /* back to old pos cursor */
Erik Andersenf0657d32000-04-12 17:49:52 +0000451}
452
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000453#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +0000454static void put(void)
455{
456 int ocursor, j = delp - delbuf;
457 if (j == 0)
458 return;
459 ocursor = cursor;
460 /* open hole and then fill it */
461 memmove(command_ps + cursor + j, command_ps + cursor, len - cursor + 1);
462 strncpy(command_ps + cursor, delbuf, j);
463 len += j;
464 input_end(); /* rewrite new line */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000465 input_backward(cursor - ocursor - j + 1); /* at end of new text */
Paul Fox3f11b1b2005-08-04 19:04:46 +0000466}
467#endif
468
Mark Whitley4e338752001-01-26 20:42:23 +0000469/* Delete the char in back of the cursor */
470static void input_backspace(void)
471{
472 if (cursor > 0) {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000473 input_backward(1);
Paul Fox3f11b1b2005-08-04 19:04:46 +0000474 input_delete(0);
Mark Whitley4e338752001-01-26 20:42:23 +0000475 }
476}
477
478
Eric Andersenaff114c2004-04-14 17:51:38 +0000479/* Move forward one character */
Mark Whitley4e338752001-01-26 20:42:23 +0000480static void input_forward(void)
Erik Andersenf0657d32000-04-12 17:49:52 +0000481{
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000482 if (cursor < len)
483 cmdedit_set_out_char(command_ps[cursor + 1]);
Erik Andersenf0657d32000-04-12 17:49:52 +0000484}
485
Mark Whitley4e338752001-01-26 20:42:23 +0000486static void cmdedit_setwidth(int w, int redraw_flg)
487{
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000488 cmdedit_termw = cmdedit_prmt_len + 2;
Eric Andersen6faae7d2001-02-16 20:09:17 +0000489 if (w <= cmdedit_termw) {
490 cmdedit_termw = cmdedit_termw % w;
491 }
Mark Whitley4e338752001-01-26 20:42:23 +0000492 if (w > cmdedit_termw) {
Mark Whitley4e338752001-01-26 20:42:23 +0000493 cmdedit_termw = w;
494
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000495 if (redraw_flg) {
496 /* new y for current cursor */
497 int new_y = (cursor + cmdedit_prmt_len) / w;
Mark Whitley4e338752001-01-26 20:42:23 +0000498
499 /* redraw */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000500 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
501 fflush(stdout);
Mark Whitley4e338752001-01-26 20:42:23 +0000502 }
Eric Andersenc470f442003-07-28 09:56:35 +0000503 }
Mark Whitley4e338752001-01-26 20:42:23 +0000504}
505
Eric Andersen7467c8d2001-07-12 20:26:32 +0000506static void cmdedit_init(void)
Mark Whitley4e338752001-01-26 20:42:23 +0000507{
Eric Andersen61173a52001-03-19 17:48:55 +0000508 cmdedit_prmt_len = 0;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000509 if (!(handlers_sets & SET_WCHG_HANDLERS)) {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000510 /* emulate usage handler to set handler and call yours work */
Mark Whitley4e338752001-01-26 20:42:23 +0000511 win_changed(-SIGWINCH);
512 handlers_sets |= SET_WCHG_HANDLERS;
513 }
514
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000515 if (!(handlers_sets & SET_ATEXIT)) {
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000516#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000517 struct passwd *entry;
518
519 my_euid = geteuid();
520 entry = getpwuid(my_euid);
521 if (entry) {
Rob Landleyd921b2e2006-08-03 15:41:12 +0000522 user_buf = xstrdup(entry->pw_name);
523 home_pwd_buf = xstrdup(entry->pw_dir);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000524 }
525#endif
526
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000527#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000528
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000529#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000530 my_euid = geteuid();
531#endif
532 my_uid = getuid();
533 my_gid = getgid();
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000534#endif /* FEATURE_COMMAND_TAB_COMPLETION */
Mark Whitley4e338752001-01-26 20:42:23 +0000535 handlers_sets |= SET_ATEXIT;
Eric Andersenc470f442003-07-28 09:56:35 +0000536 atexit(cmdedit_reset_term); /* be sure to do this only once */
Mark Whitley4e338752001-01-26 20:42:23 +0000537 }
Mark Whitley4e338752001-01-26 20:42:23 +0000538}
Erik Andersenf0657d32000-04-12 17:49:52 +0000539
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000540#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Mark Whitley4e338752001-01-26 20:42:23 +0000541
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000542static char **matches;
543static int num_matches;
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000544
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000545static void add_match(char *matched)
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000546{
547 int nm = num_matches;
548 int nm1 = nm + 1;
549
550 matches = xrealloc(matches, nm1 * sizeof(char *));
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000551 matches[nm] = matched;
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000552 num_matches++;
553}
554
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000555/*
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000556static int is_execute(const struct stat *st)
Erik Andersen6273f652000-03-17 01:12:41 +0000557{
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000558 if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
559 || (my_uid == st->st_uid && (st->st_mode & S_IXUSR))
560 || (my_gid == st->st_gid && (st->st_mode & S_IXGRP))
561 || (st->st_mode & S_IXOTH)
562 ) {
563 return TRUE;
564 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000565 return FALSE;
Erik Andersen6273f652000-03-17 01:12:41 +0000566}
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000567*/
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000568
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000569#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000570
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000571static void username_tab_completion(char *ud, char *with_shash_flg)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000572{
573 struct passwd *entry;
574 int userlen;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000575
Eric Andersenc470f442003-07-28 09:56:35 +0000576 ud++; /* ~user/... to user/... */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000577 userlen = strlen(ud);
578
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000579 if (with_shash_flg) { /* "~/..." or "~user/..." */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000580 char *sav_ud = ud - 1;
581 char *home = 0;
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000582 char *temp;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000583
Eric Andersenc470f442003-07-28 09:56:35 +0000584 if (*ud == '/') { /* "~/..." */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000585 home = home_pwd_buf;
586 } else {
587 /* "~user/..." */
588 temp = strchr(ud, '/');
Eric Andersenc470f442003-07-28 09:56:35 +0000589 *temp = 0; /* ~user\0 */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000590 entry = getpwnam(ud);
Eric Andersenc470f442003-07-28 09:56:35 +0000591 *temp = '/'; /* restore ~user/... */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000592 ud = temp;
593 if (entry)
594 home = entry->pw_dir;
595 }
596 if (home) {
597 if ((userlen + strlen(home) + 1) < BUFSIZ) {
Eric Andersenc470f442003-07-28 09:56:35 +0000598 char temp2[BUFSIZ]; /* argument size */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000599
600 /* /home/user/... */
601 sprintf(temp2, "%s%s", home, ud);
602 strcpy(sav_ud, temp2);
603 }
604 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000605 } else {
606 /* "~[^/]*" */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000607 setpwent();
608
609 while ((entry = getpwent()) != NULL) {
610 /* Null usernames should result in all users as possible completions. */
611 if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000612 add_match(xasprintf("~%s/", entry->pw_name));
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000613 }
614 }
615
616 endpwent();
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000617 }
618}
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000619#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */
Mark Whitley4e338752001-01-26 20:42:23 +0000620
621enum {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000622 FIND_EXE_ONLY = 0,
623 FIND_DIR_ONLY = 1,
Mark Whitley4e338752001-01-26 20:42:23 +0000624 FIND_FILE_ONLY = 2,
625};
Erik Andersen1dbe3402000-03-19 10:46:06 +0000626
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000627#if ENABLE_ASH
Glenn L McGrath67285962004-01-14 09:34:51 +0000628const char *cmdedit_path_lookup;
629#else
630#define cmdedit_path_lookup getenv("PATH")
631#endif
632
Mark Whitley4e338752001-01-26 20:42:23 +0000633static int path_parse(char ***p, int flags)
634{
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000635 int npth;
Glenn L McGrath67285962004-01-14 09:34:51 +0000636 const char *tmp;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000637 const char *pth = cmdedit_path_lookup;
Mark Whitley4e338752001-01-26 20:42:23 +0000638
Mark Whitley4e338752001-01-26 20:42:23 +0000639 /* if not setenv PATH variable, to search cur dir "." */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000640 if (flags != FIND_EXE_ONLY)
Mark Whitley4e338752001-01-26 20:42:23 +0000641 return 1;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000642 /* PATH=<empty> or PATH=:<empty> */
643 if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
644 return 1;
Mark Whitley4e338752001-01-26 20:42:23 +0000645
646 tmp = pth;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000647 npth = 0;
Mark Whitley4e338752001-01-26 20:42:23 +0000648
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000649 while (1) {
Eric Andersenc470f442003-07-28 09:56:35 +0000650 npth++; /* count words is + 1 count ':' */
Mark Whitley4e338752001-01-26 20:42:23 +0000651 tmp = strchr(tmp, ':');
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000652 if (!tmp)
Mark Whitley4e338752001-01-26 20:42:23 +0000653 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000654 if (*++tmp == 0)
655 break; /* :<empty> */
Mark Whitley4e338752001-01-26 20:42:23 +0000656 }
657
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000658 *p = xmalloc(npth * sizeof(char *));
Mark Whitley4e338752001-01-26 20:42:23 +0000659
660 tmp = pth;
Rob Landleyd921b2e2006-08-03 15:41:12 +0000661 (*p)[0] = xstrdup(tmp);
Eric Andersenc470f442003-07-28 09:56:35 +0000662 npth = 1; /* count words is + 1 count ':' */
Mark Whitley4e338752001-01-26 20:42:23 +0000663
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000664 while (1) {
Mark Whitley4e338752001-01-26 20:42:23 +0000665 tmp = strchr(tmp, ':');
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000666 if (!tmp)
Mark Whitley4e338752001-01-26 20:42:23 +0000667 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000668 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */
669 if (*++tmp == 0)
670 break; /* :<empty> */
Eric Andersenc470f442003-07-28 09:56:35 +0000671 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */
Mark Whitley4e338752001-01-26 20:42:23 +0000672 }
673
674 return npth;
675}
676
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000677static char *add_quote_for_spec_chars(char *found)
Erik Andersen6273f652000-03-17 01:12:41 +0000678{
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000679 int l = 0;
680 char *s = xmalloc((strlen(found) + 1) * 2);
681
682 while (*found) {
683 if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
684 s[l++] = '\\';
685 s[l++] = *found++;
686 }
687 s[l] = 0;
688 return s;
689}
690
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000691static void exe_n_cwd_tab_completion(char *command, int type)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000692{
Erik Andersen1dbe3402000-03-19 10:46:06 +0000693 DIR *dir;
694 struct dirent *next;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000695 char dirbuf[BUFSIZ];
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000696 struct stat st;
697 char *path1[1];
698 char **paths = path1;
699 int npaths;
700 int i;
Eric Andersene5dfced2001-04-09 22:48:12 +0000701 char *found;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000702 char *pfind = strrchr(command, '/');
Mark Whitley4e338752001-01-26 20:42:23 +0000703
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000704 path1[0] = ".";
Mark Whitley4e338752001-01-26 20:42:23 +0000705
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000706 if (pfind == NULL) {
Mark Whitley4e338752001-01-26 20:42:23 +0000707 /* no dir, if flags==EXE_ONLY - get paths, else "." */
708 npaths = path_parse(&paths, type);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000709 pfind = command;
Mark Whitley4e338752001-01-26 20:42:23 +0000710 } else {
711 /* with dir */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000712 /* save for change */
713 strcpy(dirbuf, command);
714 /* set dir only */
715 dirbuf[(pfind - command) + 1] = 0;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000716#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
Eric Andersenc470f442003-07-28 09:56:35 +0000717 if (dirbuf[0] == '~') /* ~/... or ~user/... */
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000718 username_tab_completion(dirbuf, dirbuf);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000719#endif
720 /* "strip" dirname in command */
721 pfind++;
Mark Whitley4e338752001-01-26 20:42:23 +0000722
Mark Whitley4e338752001-01-26 20:42:23 +0000723 paths[0] = dirbuf;
Eric Andersenc470f442003-07-28 09:56:35 +0000724 npaths = 1; /* only 1 dir */
Mark Whitley4e338752001-01-26 20:42:23 +0000725 }
Erik Andersenc7c634b2000-03-19 05:28:55 +0000726
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000727 for (i = 0; i < npaths; i++) {
Erik Andersenc7c634b2000-03-19 05:28:55 +0000728
Mark Whitley4e338752001-01-26 20:42:23 +0000729 dir = opendir(paths[i]);
Eric Andersenc470f442003-07-28 09:56:35 +0000730 if (!dir) /* Don't print an error */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000731 continue;
732
733 while ((next = readdir(dir)) != NULL) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000734 int len1;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000735 char *str_found = next->d_name;
736
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000737 /* matched? */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000738 if (strncmp(str_found, pfind, strlen(pfind)))
Mark Whitley4e338752001-01-26 20:42:23 +0000739 continue;
740 /* not see .name without .match */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000741 if (*str_found == '.' && *pfind == 0) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000742 if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
Mark Whitley4e338752001-01-26 20:42:23 +0000743 continue;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000744 str_found = ""; /* only "/" */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000745 }
Eric Andersene5dfced2001-04-09 22:48:12 +0000746 found = concat_path_file(paths[i], str_found);
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000747 /* hmm, remover in progress? */
Eric Andersenc470f442003-07-28 09:56:35 +0000748 if (stat(found, &st) < 0)
Eric Andersene5dfced2001-04-09 22:48:12 +0000749 goto cont;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000750 /* find with dirs? */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000751 if (paths[i] != dirbuf)
Eric Andersenc470f442003-07-28 09:56:35 +0000752 strcpy(found, next->d_name); /* only name */
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000753
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000754 len1 = strlen(found);
755 found = xrealloc(found, len1 + 2);
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000756 found[len1] = '\0';
757 found[len1+1] = '\0';
758
Mark Whitley4e338752001-01-26 20:42:23 +0000759 if (S_ISDIR(st.st_mode)) {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000760 /* name is directory */
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000761 if (found[len1-1] != '/') {
762 found[len1] = '/';
763 }
Mark Whitley4e338752001-01-26 20:42:23 +0000764 } else {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000765 /* not put found file if search only dirs for cd */
Eric Andersenc470f442003-07-28 09:56:35 +0000766 if (type == FIND_DIR_ONLY)
Eric Andersene5dfced2001-04-09 22:48:12 +0000767 goto cont;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000768 }
Mark Whitley4e338752001-01-26 20:42:23 +0000769 /* Add it to the list */
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000770 add_match(found);
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000771 continue;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000772 cont:
Eric Andersene5dfced2001-04-09 22:48:12 +0000773 free(found);
Erik Andersen1dbe3402000-03-19 10:46:06 +0000774 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000775 closedir(dir);
Erik Andersen1dbe3402000-03-19 10:46:06 +0000776 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000777 if (paths != path1) {
Eric Andersenc470f442003-07-28 09:56:35 +0000778 free(paths[0]); /* allocated memory only in first member */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000779 free(paths);
780 }
Erik Andersen6273f652000-03-17 01:12:41 +0000781}
Erik Andersenf0657d32000-04-12 17:49:52 +0000782
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000783
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000784#define QUOT (UCHAR_MAX+1)
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000785
786#define collapse_pos(is, in) { \
Paul Fox574fee42005-07-19 20:41:06 +0000787 memmove(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
788 memmove(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000789
790static int find_match(char *matchBuf, int *len_with_quotes)
791{
792 int i, j;
793 int command_mode;
794 int c, c2;
795 int int_buf[BUFSIZ + 1];
796 int pos_buf[BUFSIZ + 1];
797
798 /* set to integer dimension characters and own positions */
799 for (i = 0;; i++) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000800 int_buf[i] = (unsigned char)matchBuf[i];
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000801 if (int_buf[i] == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +0000802 pos_buf[i] = -1; /* indicator end line */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000803 break;
804 } else
805 pos_buf[i] = i;
806 }
807
808 /* mask \+symbol and convert '\t' to ' ' */
809 for (i = j = 0; matchBuf[i]; i++, j++)
810 if (matchBuf[i] == '\\') {
811 collapse_pos(j, j + 1);
812 int_buf[j] |= QUOT;
813 i++;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000814#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersenc470f442003-07-28 09:56:35 +0000815 if (matchBuf[i] == '\t') /* algorithm equivalent */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000816 int_buf[j] = ' ' | QUOT;
817#endif
818 }
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000819#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000820 else if (matchBuf[i] == '\t')
821 int_buf[j] = ' ';
822#endif
823
824 /* mask "symbols" or 'symbols' */
825 c2 = 0;
826 for (i = 0; int_buf[i]; i++) {
827 c = int_buf[i];
828 if (c == '\'' || c == '"') {
829 if (c2 == 0)
830 c2 = c;
831 else {
832 if (c == c2)
833 c2 = 0;
834 else
835 int_buf[i] |= QUOT;
836 }
837 } else if (c2 != 0 && c != '$')
838 int_buf[i] |= QUOT;
839 }
840
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000841 /* skip commands with arguments if line has commands delimiters */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000842 /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
843 for (i = 0; int_buf[i]; i++) {
844 c = int_buf[i];
845 c2 = int_buf[i + 1];
846 j = i ? int_buf[i - 1] : -1;
847 command_mode = 0;
848 if (c == ';' || c == '&' || c == '|') {
849 command_mode = 1 + (c == c2);
850 if (c == '&') {
851 if (j == '>' || j == '<')
852 command_mode = 0;
853 } else if (c == '|' && j == '>')
854 command_mode = 0;
855 }
856 if (command_mode) {
857 collapse_pos(0, i + command_mode);
Eric Andersenc470f442003-07-28 09:56:35 +0000858 i = -1; /* hack incremet */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000859 }
860 }
861 /* collapse `command...` */
862 for (i = 0; int_buf[i]; i++)
863 if (int_buf[i] == '`') {
864 for (j = i + 1; int_buf[j]; j++)
865 if (int_buf[j] == '`') {
866 collapse_pos(i, j + 1);
867 j = 0;
868 break;
869 }
870 if (j) {
871 /* not found close ` - command mode, collapse all previous */
872 collapse_pos(0, i + 1);
873 break;
874 } else
Eric Andersenc470f442003-07-28 09:56:35 +0000875 i--; /* hack incremet */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000876 }
877
878 /* collapse (command...(command...)...) or {command...{command...}...} */
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000879 c = 0; /* "recursive" level */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000880 c2 = 0;
881 for (i = 0; int_buf[i]; i++)
882 if (int_buf[i] == '(' || int_buf[i] == '{') {
883 if (int_buf[i] == '(')
884 c++;
885 else
886 c2++;
887 collapse_pos(0, i + 1);
Eric Andersenc470f442003-07-28 09:56:35 +0000888 i = -1; /* hack incremet */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000889 }
890 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
891 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
892 if (int_buf[i] == ')')
893 c--;
894 else
895 c2--;
896 collapse_pos(0, i + 1);
Eric Andersenc470f442003-07-28 09:56:35 +0000897 i = -1; /* hack incremet */
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000898 }
899
900 /* skip first not quote space */
901 for (i = 0; int_buf[i]; i++)
902 if (int_buf[i] != ' ')
903 break;
904 if (i)
905 collapse_pos(0, i);
906
907 /* set find mode for completion */
908 command_mode = FIND_EXE_ONLY;
909 for (i = 0; int_buf[i]; i++)
910 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
911 if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000912 && matchBuf[pos_buf[0]]=='c'
913 && matchBuf[pos_buf[1]]=='d'
914 ) {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000915 command_mode = FIND_DIR_ONLY;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000916 } else {
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000917 command_mode = FIND_FILE_ONLY;
918 break;
919 }
920 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000921 for (i = 0; int_buf[i]; i++)
922 /* "strlen" */;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000923 /* find last word */
924 for (--i; i >= 0; i--) {
925 c = int_buf[i];
926 if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
927 collapse_pos(0, i + 1);
928 break;
929 }
930 }
931 /* skip first not quoted '\'' or '"' */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000932 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
933 /*skip*/;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000934 /* collapse quote or unquote // or /~ */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000935 while ((int_buf[i] & ~QUOT) == '/'
936 && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
937 ) {
Mark Whitley7e5291f2001-03-08 19:31:12 +0000938 i++;
939 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000940
941 /* set only match and destroy quotes */
942 j = 0;
Eric Andersen4f990532001-05-31 17:15:57 +0000943 for (c = 0; pos_buf[i] >= 0; i++) {
944 matchBuf[c++] = matchBuf[pos_buf[i]];
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000945 j = pos_buf[i] + 1;
946 }
Eric Andersen4f990532001-05-31 17:15:57 +0000947 matchBuf[c] = 0;
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000948 /* old lenght matchBuf with quotes symbols */
949 *len_with_quotes = j ? j - pos_buf[0] : 0;
950
951 return command_mode;
952}
953
Glenn L McGrath4d001292003-01-06 01:11:50 +0000954/*
955 display by column original ideas from ls applet,
956 very optimize by my :)
957*/
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000958static void showfiles(void)
Glenn L McGrath4d001292003-01-06 01:11:50 +0000959{
960 int ncols, row;
961 int column_width = 0;
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000962 int nfiles = num_matches;
Glenn L McGrath4d001292003-01-06 01:11:50 +0000963 int nrows = nfiles;
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000964 int l;
Glenn L McGrath4d001292003-01-06 01:11:50 +0000965
966 /* find the longest file name- use that as the column width */
967 for (row = 0; row < nrows; row++) {
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000968 l = strlen(matches[row]);
Glenn L McGrath4d001292003-01-06 01:11:50 +0000969 if (column_width < l)
970 column_width = l;
971 }
972 column_width += 2; /* min space for columns */
973 ncols = cmdedit_termw / column_width;
974
975 if (ncols > 1) {
976 nrows /= ncols;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +0000977 if (nfiles % ncols)
Glenn L McGrath4d001292003-01-06 01:11:50 +0000978 nrows++; /* round up fractionals */
Glenn L McGrath4d001292003-01-06 01:11:50 +0000979 } else {
980 ncols = 1;
981 }
982 for (row = 0; row < nrows; row++) {
983 int n = row;
984 int nc;
985
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000986 for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000987 printf("%s%-*s", matches[n],
Denis Vlasenko0a8a7742006-12-21 22:27:10 +0000988 column_width - strlen(matches[n]), "");
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +0000989 }
Denis Vlasenkod56b47f2006-12-21 22:24:46 +0000990 printf("%s\n", matches[n]);
Glenn L McGrath4d001292003-01-06 01:11:50 +0000991 }
992}
993
Denis Vlasenkof58906b2006-12-19 19:30:37 +0000994static int match_compare(const void *a, const void *b)
995{
996 return strcmp(*(char**)a, *(char**)b);
997}
998
Eric Andersen5f2c79d2001-02-16 18:36:04 +0000999static void input_tab(int *lastWasTab)
Erik Andersenf0657d32000-04-12 17:49:52 +00001000{
1001 /* Do TAB completion */
Eric Andersenc470f442003-07-28 09:56:35 +00001002 if (lastWasTab == 0) { /* free all memory */
Erik Andersenf0657d32000-04-12 17:49:52 +00001003 if (matches) {
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001004 while (num_matches > 0)
Mark Whitley4e338752001-01-26 20:42:23 +00001005 free(matches[--num_matches]);
Erik Andersenf0657d32000-04-12 17:49:52 +00001006 free(matches);
1007 matches = (char **) NULL;
1008 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001009 return;
1010 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001011 if (!*lastWasTab) {
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001012 char *tmp, *tmp1;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001013 int len_found;
1014 char matchBuf[BUFSIZ];
1015 int find_type;
1016 int recalc_pos;
1017
Eric Andersenc470f442003-07-28 09:56:35 +00001018 *lastWasTab = TRUE; /* flop trigger */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001019
1020 /* Make a local copy of the string -- up
1021 * to the position of the cursor */
1022 tmp = strncpy(matchBuf, command_ps, cursor);
1023 tmp[cursor] = 0;
1024
1025 find_type = find_match(matchBuf, &recalc_pos);
1026
1027 /* Free up any memory already allocated */
1028 input_tab(0);
Erik Andersenf0657d32000-04-12 17:49:52 +00001029
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001030#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001031 /* If the word starts with `~' and there is no slash in the word,
Erik Andersenf0657d32000-04-12 17:49:52 +00001032 * then try completing this word as a username. */
1033
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001034 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001035 username_tab_completion(matchBuf, NULL);
1036 if (!matches)
Mark Whitley4e338752001-01-26 20:42:23 +00001037#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001038 /* Try to match any executable in our path and everything
Erik Andersenf0657d32000-04-12 17:49:52 +00001039 * in the current working directory that matches. */
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001040 exe_n_cwd_tab_completion(matchBuf, find_type);
Denis Vlasenkof58906b2006-12-19 19:30:37 +00001041 /* Sort, then remove any duplicates found */
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001042 if (matches) {
Denis Vlasenkof58906b2006-12-19 19:30:37 +00001043 int i, n = 0;
1044 qsort(matches, num_matches, sizeof(char*), match_compare);
1045 for (i = 0; i < num_matches - 1; ++i) {
1046 if (matches[i] && matches[i+1]) {
1047 if (strcmp(matches[i], matches[i+1]) == 0) {
1048 free(matches[i]);
1049 matches[i] = 0;
1050 } else {
Denis Vlasenkof58906b2006-12-19 19:30:37 +00001051 matches[n++] = matches[i];
Denis Vlasenko92758142006-10-03 19:56:34 +00001052 }
Glenn L McGrath78b0e372001-06-26 02:06:08 +00001053 }
Denis Vlasenko92758142006-10-03 19:56:34 +00001054 }
Denis Vlasenkof58906b2006-12-19 19:30:37 +00001055 matches[n++] = matches[num_matches-1];
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001056 num_matches = n;
Glenn L McGrath78b0e372001-06-26 02:06:08 +00001057 }
Erik Andersenf0657d32000-04-12 17:49:52 +00001058 /* Did we find exactly one match? */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001059 if (!matches || num_matches > 1) {
Mark Whitley4e338752001-01-26 20:42:23 +00001060 beep();
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001061 if (!matches)
Eric Andersenc470f442003-07-28 09:56:35 +00001062 return; /* not found */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001063 /* find minimal match */
Rob Landleyd921b2e2006-08-03 15:41:12 +00001064 tmp1 = xstrdup(matches[0]);
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001065 for (tmp = tmp1; *tmp; tmp++)
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001066 for (len_found = 1; len_found < num_matches; len_found++)
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001067 if (matches[len_found][(tmp - tmp1)] != *tmp) {
1068 *tmp = 0;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001069 break;
1070 }
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001071 if (*tmp1 == 0) { /* have unique */
1072 free(tmp1);
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001073 return;
1074 }
Denis Vlasenkod56b47f2006-12-21 22:24:46 +00001075 tmp = add_quote_for_spec_chars(tmp1);
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001076 free(tmp1);
Eric Andersenc470f442003-07-28 09:56:35 +00001077 } else { /* one match */
Denis Vlasenkod56b47f2006-12-21 22:24:46 +00001078 tmp = add_quote_for_spec_chars(matches[0]);
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001079 /* for next completion current found */
1080 *lastWasTab = FALSE;
Denis Vlasenkod56b47f2006-12-21 22:24:46 +00001081
1082 len_found = strlen(tmp);
1083 if (tmp[len_found-1] != '/') {
1084 tmp[len_found] = ' ';
1085 tmp[len_found+1] = '\0';
1086 }
Mark Whitley4e338752001-01-26 20:42:23 +00001087 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001088 len_found = strlen(tmp);
Mark Whitley4e338752001-01-26 20:42:23 +00001089 /* have space to placed match? */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001090 if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
Mark Whitley4e338752001-01-26 20:42:23 +00001091
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001092 /* before word for match */
1093 command_ps[cursor - recalc_pos] = 0;
1094 /* save tail line */
1095 strcpy(matchBuf, command_ps + cursor);
1096 /* add match */
1097 strcat(command_ps, tmp);
1098 /* add tail */
Mark Whitley4e338752001-01-26 20:42:23 +00001099 strcat(command_ps, matchBuf);
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001100 /* back to begin word for match */
1101 input_backward(recalc_pos);
1102 /* new pos */
1103 recalc_pos = cursor + len_found;
1104 /* new len */
1105 len = strlen(command_ps);
1106 /* write out the matched command */
Eric Andersen4f990532001-05-31 17:15:57 +00001107 redraw(cmdedit_y, len - recalc_pos);
Erik Andersenf0657d32000-04-12 17:49:52 +00001108 }
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001109 free(tmp);
Erik Andersenf0657d32000-04-12 17:49:52 +00001110 } else {
1111 /* Ok -- the last char was a TAB. Since they
1112 * just hit TAB again, print a list of all the
1113 * available choices... */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001114 if (matches && num_matches > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00001115 int sav_cursor = cursor; /* change goto_new_line() */
Erik Andersenf0657d32000-04-12 17:49:52 +00001116
1117 /* Go to the next line */
Mark Whitley4e338752001-01-26 20:42:23 +00001118 goto_new_line();
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001119 showfiles();
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001120 redraw(0, len - sav_cursor);
Erik Andersenf0657d32000-04-12 17:49:52 +00001121 }
1122 }
1123}
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001124#endif /* FEATURE_COMMAND_TAB_COMPLETION */
Erik Andersenf0657d32000-04-12 17:49:52 +00001125
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001126#if MAX_HISTORY > 0
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001127static void get_previous_history(void)
Erik Andersenf0657d32000-04-12 17:49:52 +00001128{
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001129 if (command_ps[0] != 0 || history[cur_history] == 0) {
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001130 free(history[cur_history]);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001131 history[cur_history] = xstrdup(command_ps);
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001132 }
1133 cur_history--;
Erik Andersenf0657d32000-04-12 17:49:52 +00001134}
1135
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001136static int get_next_history(void)
Erik Andersenf0657d32000-04-12 17:49:52 +00001137{
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001138 int ch = cur_history;
1139
1140 if (ch < n_history) {
1141 get_previous_history(); /* save the current history line */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001142 cur_history = ch + 1;
1143 return cur_history;
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001144 } else {
1145 beep();
1146 return 0;
1147 }
Erik Andersenf0657d32000-04-12 17:49:52 +00001148}
Robert Griebl350d26b2002-12-03 22:45:46 +00001149
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001150#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001151void load_history(const char *fromfile)
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001152{
Robert Griebl350d26b2002-12-03 22:45:46 +00001153 FILE *fp;
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001154 int hi;
Robert Griebl350d26b2002-12-03 22:45:46 +00001155
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001156 /* cleanup old */
1157
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001158 for (hi = n_history; hi > 0;) {
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001159 hi--;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001160 free(history[hi]);
Robert Griebl350d26b2002-12-03 22:45:46 +00001161 }
1162
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001163 fp = fopen(fromfile, "r");
1164 if (fp) {
1165 for (hi = 0; hi < MAX_HISTORY;) {
Denis Vlasenko2d5ca602006-10-12 22:43:20 +00001166 char * hl = xmalloc_getline(fp);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001167 int l;
1168
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001169 if (!hl)
Robert Griebl350d26b2002-12-03 22:45:46 +00001170 break;
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001171 l = strlen(hl);
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001172 if (l >= BUFSIZ)
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001173 hl[BUFSIZ-1] = 0;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001174 if (l == 0 || hl[0] == ' ') {
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001175 free(hl);
1176 continue;
1177 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001178 history[hi++] = hl;
Robert Griebl350d26b2002-12-03 22:45:46 +00001179 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001180 fclose(fp);
Robert Griebl350d26b2002-12-03 22:45:46 +00001181 }
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001182 cur_history = n_history = hi;
Robert Griebl350d26b2002-12-03 22:45:46 +00001183}
1184
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001185void save_history (const char *tofile)
Robert Griebl350d26b2002-12-03 22:45:46 +00001186{
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001187 FILE *fp = fopen(tofile, "w");
Eric Andersenc470f442003-07-28 09:56:35 +00001188
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001189 if (fp) {
Robert Griebl350d26b2002-12-03 22:45:46 +00001190 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00001191
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001192 for (i = 0; i < n_history; i++) {
1193 fprintf(fp, "%s\n", history[i]);
Robert Griebl350d26b2002-12-03 22:45:46 +00001194 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001195 fclose(fp);
Robert Griebl350d26b2002-12-03 22:45:46 +00001196 }
Robert Griebl350d26b2002-12-03 22:45:46 +00001197}
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001198#endif
Robert Griebl350d26b2002-12-03 22:45:46 +00001199
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001200#endif
Erik Andersenf0657d32000-04-12 17:49:52 +00001201
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001202enum {
1203 ESC = 27,
1204 DEL = 127,
1205};
1206
1207
Erik Andersen6273f652000-03-17 01:12:41 +00001208/*
1209 * This function is used to grab a character buffer
1210 * from the input file descriptor and allows you to
Eric Andersen9b3ce772004-04-12 15:03:51 +00001211 * a string with full command editing (sort of like
Erik Andersen6273f652000-03-17 01:12:41 +00001212 * a mini readline).
1213 *
1214 * The following standard commands are not implemented:
1215 * ESC-b -- Move back one word
1216 * ESC-f -- Move forward one word
1217 * ESC-d -- Delete back one word
1218 * ESC-h -- Delete forward one word
1219 * CTL-t -- Transpose two characters
1220 *
Paul Fox3f11b1b2005-08-04 19:04:46 +00001221 * Minimalist vi-style command line editing available if configured.
1222 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
Erik Andersen6273f652000-03-17 01:12:41 +00001223 *
Erik Andersen6273f652000-03-17 01:12:41 +00001224 */
Eric Andersenc470f442003-07-28 09:56:35 +00001225
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001226#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +00001227static int vi_mode;
1228
1229void setvimode ( int viflag )
1230{
1231 vi_mode = viflag;
1232}
1233
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001234static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001235vi_Word_motion(char *command, int eat)
1236{
1237 while (cursor < len && !isspace(command[cursor]))
1238 input_forward();
1239 if (eat) while (cursor < len && isspace(command[cursor]))
1240 input_forward();
1241}
1242
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001243static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001244vi_word_motion(char *command, int eat)
1245{
1246 if (isalnum(command[cursor]) || command[cursor] == '_') {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001247 while (cursor < len
1248 && (isalnum(command[cursor+1]) || command[cursor+1] == '_'))
Paul Fox3f11b1b2005-08-04 19:04:46 +00001249 input_forward();
1250 } else if (ispunct(command[cursor])) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001251 while (cursor < len && ispunct(command[cursor+1]))
Paul Fox3f11b1b2005-08-04 19:04:46 +00001252 input_forward();
1253 }
1254
1255 if (cursor < len)
1256 input_forward();
1257
1258 if (eat && cursor < len && isspace(command[cursor]))
1259 while (cursor < len && isspace(command[cursor]))
1260 input_forward();
1261}
1262
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001263static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001264vi_End_motion(char *command)
1265{
1266 input_forward();
1267 while (cursor < len && isspace(command[cursor]))
1268 input_forward();
1269 while (cursor < len-1 && !isspace(command[cursor+1]))
1270 input_forward();
1271}
1272
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001273static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001274vi_end_motion(char *command)
1275{
1276 if (cursor >= len-1)
1277 return;
1278 input_forward();
1279 while (cursor < len-1 && isspace(command[cursor]))
1280 input_forward();
1281 if (cursor >= len-1)
1282 return;
1283 if (isalnum(command[cursor]) || command[cursor] == '_') {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001284 while (cursor < len-1
1285 && (isalnum(command[cursor+1]) || command[cursor+1] == '_')
1286 ) {
Paul Fox3f11b1b2005-08-04 19:04:46 +00001287 input_forward();
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001288 }
Paul Fox3f11b1b2005-08-04 19:04:46 +00001289 } else if (ispunct(command[cursor])) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001290 while (cursor < len-1 && ispunct(command[cursor+1]))
Paul Fox3f11b1b2005-08-04 19:04:46 +00001291 input_forward();
1292 }
1293}
1294
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001295static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001296vi_Back_motion(char *command)
1297{
1298 while (cursor > 0 && isspace(command[cursor-1]))
1299 input_backward(1);
1300 while (cursor > 0 && !isspace(command[cursor-1]))
1301 input_backward(1);
1302}
1303
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +00001304static void
Paul Fox3f11b1b2005-08-04 19:04:46 +00001305vi_back_motion(char *command)
1306{
1307 if (cursor <= 0)
1308 return;
1309 input_backward(1);
1310 while (cursor > 0 && isspace(command[cursor]))
1311 input_backward(1);
1312 if (cursor <= 0)
1313 return;
1314 if (isalnum(command[cursor]) || command[cursor] == '_') {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001315 while (cursor > 0
1316 && (isalnum(command[cursor-1]) || command[cursor-1] == '_')
1317 ) {
Paul Fox3f11b1b2005-08-04 19:04:46 +00001318 input_backward(1);
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001319 }
Paul Fox3f11b1b2005-08-04 19:04:46 +00001320 } else if (ispunct(command[cursor])) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001321 while (cursor > 0 && ispunct(command[cursor-1]))
Paul Fox3f11b1b2005-08-04 19:04:46 +00001322 input_backward(1);
1323 }
1324}
1325#endif
1326
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001327/*
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001328 * the emacs and vi modes share much of the code in the big
1329 * command loop. commands entered when in vi's command mode (aka
1330 * "escape mode") get an extra bit added to distinguish them --
1331 * this keeps them from being self-inserted. this clutters the
1332 * big switch a bit, but keeps all the code in one place.
Paul Fox3f11b1b2005-08-04 19:04:46 +00001333 */
1334
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001335#define vbit 0x100
1336
1337/* leave out the "vi-mode"-only case labels if vi editing isn't
1338 * configured. */
1339#define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel)
Paul Fox3f11b1b2005-08-04 19:04:46 +00001340
1341/* convert uppercase ascii to equivalent control char, for readability */
1342#define CNTRL(uc_char) ((uc_char) - 0x40)
1343
Eric Andersen044228d2001-07-17 01:12:36 +00001344
1345int cmdedit_read_input(char *prompt, char command[BUFSIZ])
Erik Andersen13456d12000-03-16 08:09:57 +00001346{
Erik Andersenc7c634b2000-03-19 05:28:55 +00001347 int break_out = 0;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001348 int lastWasTab = FALSE;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001349 unsigned char c;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001350 unsigned int ic;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001351#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001352 unsigned int prevc;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001353 int vi_cmdmode = 0;
1354#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001355 /* prepare before init handlers */
Eric Andersenc470f442003-07-28 09:56:35 +00001356 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
Mark Whitley4e338752001-01-26 20:42:23 +00001357 len = 0;
Mark Whitley4e338752001-01-26 20:42:23 +00001358 command_ps = command;
1359
Eric Andersen34506362001-08-02 05:02:46 +00001360 getTermSettings(0, (void *) &initial_settings);
1361 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
1362 new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1363 /* Turn off echoing and CTRL-C, so we can trap it */
1364 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
Eric Andersen34506362001-08-02 05:02:46 +00001365 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
1366 new_settings.c_cc[VMIN] = 1;
1367 new_settings.c_cc[VTIME] = 0;
1368 /* Turn off CTRL-C, so we can trap it */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001369# ifndef _POSIX_VDISABLE
1370# define _POSIX_VDISABLE '\0'
1371# endif
Eric Andersenc470f442003-07-28 09:56:35 +00001372 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001373 command[0] = 0;
1374
Glenn L McGrath78b0e372001-06-26 02:06:08 +00001375 setTermSettings(0, (void *) &new_settings);
Mark Whitley4e338752001-01-26 20:42:23 +00001376 handlers_sets |= SET_RESET_TERM;
Erik Andersen13456d12000-03-16 08:09:57 +00001377
Eric Andersen6faae7d2001-02-16 20:09:17 +00001378 /* Now initialize things */
1379 cmdedit_init();
Eric Andersenf9ff8a72001-03-15 20:51:09 +00001380 /* Print out the command prompt */
1381 parse_prompt(prompt);
Eric Andersenb3dc3b82001-01-04 11:08:45 +00001382
Erik Andersenc7c634b2000-03-19 05:28:55 +00001383 while (1) {
Eric Andersenc470f442003-07-28 09:56:35 +00001384 fflush(stdout); /* buffered out to fast */
Mark Whitley4e338752001-01-26 20:42:23 +00001385
Eric Andersen7467c8d2001-07-12 20:26:32 +00001386 if (safe_read(0, &c, 1) < 1)
Eric Andersened424db2001-04-23 15:28:28 +00001387 /* if we can't read input then exit */
1388 goto prepare_to_die;
Erik Andersenf3b3d172000-04-09 18:24:05 +00001389
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001390 ic = c;
1391
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001392#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +00001393 newdelflag = 1;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001394 if (vi_cmdmode)
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001395 ic |= vbit;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001396#endif
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001397 switch (ic) {
Erik Andersenf0657d32000-04-12 17:49:52 +00001398 case '\n':
1399 case '\r':
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001400 vi_case( case '\n'|vbit: )
1401 vi_case( case '\r'|vbit: )
Erik Andersenf0657d32000-04-12 17:49:52 +00001402 /* Enter */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001403 goto_new_line();
Erik Andersenf0657d32000-04-12 17:49:52 +00001404 break_out = 1;
1405 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001406 case CNTRL('A'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001407 vi_case( case '0'|vbit: )
Erik Andersenc7c634b2000-03-19 05:28:55 +00001408 /* Control-a -- Beginning of line */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001409 input_backward(cursor);
Mark Whitley4e338752001-01-26 20:42:23 +00001410 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001411 case CNTRL('B'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001412 vi_case( case 'h'|vbit: )
1413 vi_case( case '\b'|vbit: )
1414 vi_case( case DEL|vbit: )
Erik Andersenf0657d32000-04-12 17:49:52 +00001415 /* Control-b -- Move back one character */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001416 input_backward(1);
Erik Andersenf0657d32000-04-12 17:49:52 +00001417 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001418 case CNTRL('C'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001419 vi_case( case CNTRL('C')|vbit: )
Eric Andersen86349772000-12-18 20:25:50 +00001420 /* Control-c -- stop gathering input */
Mark Whitley4e338752001-01-26 20:42:23 +00001421 goto_new_line();
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001422#if !ENABLE_ASH
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001423 command[0] = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +00001424 len = 0;
1425 lastWasTab = FALSE;
1426 put_prompt();
Glenn L McGrath16e45d72004-02-04 08:24:39 +00001427#else
1428 len = 0;
Glenn L McGrath7fc504c2004-02-22 11:13:28 +00001429 break_out = -1; /* to control traps */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00001430#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00001431 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001432 case CNTRL('D'):
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001433 /* Control-d -- Delete one character, or exit
Erik Andersenf0657d32000-04-12 17:49:52 +00001434 * if the len=0 and no chars to delete */
1435 if (len == 0) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001436 errno = 0;
1437 prepare_to_die:
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001438#if !ENABLE_ASH
Mark Whitley4e338752001-01-26 20:42:23 +00001439 printf("exit");
Eric Andersen7467c8d2001-07-12 20:26:32 +00001440 goto_new_line();
1441 /* cmdedit_reset_term() called in atexit */
1442 exit(EXIT_SUCCESS);
Eric Andersen044228d2001-07-17 01:12:36 +00001443#else
Glenn L McGrath7fc504c2004-02-22 11:13:28 +00001444 /* to control stopped jobs */
1445 len = break_out = -1;
Eric Andersen044228d2001-07-17 01:12:36 +00001446 break;
1447#endif
Erik Andersenf0657d32000-04-12 17:49:52 +00001448 } else {
Paul Fox3f11b1b2005-08-04 19:04:46 +00001449 input_delete(0);
Erik Andersenf0657d32000-04-12 17:49:52 +00001450 }
1451 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001452 case CNTRL('E'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001453 vi_case( case '$'|vbit: )
Erik Andersenc7c634b2000-03-19 05:28:55 +00001454 /* Control-e -- End of line */
Mark Whitley4e338752001-01-26 20:42:23 +00001455 input_end();
Erik Andersenc7c634b2000-03-19 05:28:55 +00001456 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001457 case CNTRL('F'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001458 vi_case( case 'l'|vbit: )
1459 vi_case( case ' '|vbit: )
Erik Andersenc7c634b2000-03-19 05:28:55 +00001460 /* Control-f -- Move forward one character */
Mark Whitley4e338752001-01-26 20:42:23 +00001461 input_forward();
Erik Andersenc7c634b2000-03-19 05:28:55 +00001462 break;
Erik Andersenf0657d32000-04-12 17:49:52 +00001463 case '\b':
1464 case DEL:
Erik Andersen1d1d9502000-04-21 01:26:49 +00001465 /* Control-h and DEL */
Mark Whitley4e338752001-01-26 20:42:23 +00001466 input_backspace();
Erik Andersenc7c634b2000-03-19 05:28:55 +00001467 break;
1468 case '\t':
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001469#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001470 input_tab(&lastWasTab);
Erik Andersena2685732000-04-09 18:27:46 +00001471#endif
Erik Andersenc7c634b2000-03-19 05:28:55 +00001472 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001473 case CNTRL('K'):
Eric Andersenc470f442003-07-28 09:56:35 +00001474 /* Control-k -- clear to end of line */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001475 command[cursor] = 0;
Eric Andersen65a07302002-04-13 13:26:49 +00001476 len = cursor;
Eric Andersenae103612002-04-24 23:08:23 +00001477 printf("\033[J");
Eric Andersen65a07302002-04-13 13:26:49 +00001478 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001479 case CNTRL('L'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001480 vi_case( case CNTRL('L')|vbit: )
Eric Andersen27bb7902003-12-23 20:24:51 +00001481 /* Control-l -- clear screen */
Eric Andersenc470f442003-07-28 09:56:35 +00001482 printf("\033[H");
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001483 redraw(0, len - cursor);
Eric Andersenf1f2bd02001-12-21 11:20:15 +00001484 break;
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001485#if MAX_HISTORY > 0
Paul Fox3f11b1b2005-08-04 19:04:46 +00001486 case CNTRL('N'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001487 vi_case( case CNTRL('N')|vbit: )
1488 vi_case( case 'j'|vbit: )
Erik Andersenf0657d32000-04-12 17:49:52 +00001489 /* Control-n -- Get next command in history */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001490 if (get_next_history())
Erik Andersenf0657d32000-04-12 17:49:52 +00001491 goto rewrite_line;
Erik Andersenf0657d32000-04-12 17:49:52 +00001492 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001493 case CNTRL('P'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001494 vi_case( case CNTRL('P')|vbit: )
1495 vi_case( case 'k'|vbit: )
Erik Andersenf0657d32000-04-12 17:49:52 +00001496 /* Control-p -- Get previous command from history */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001497 if (cur_history > 0) {
1498 get_previous_history();
Erik Andersenf0657d32000-04-12 17:49:52 +00001499 goto rewrite_line;
1500 } else {
Mark Whitley4e338752001-01-26 20:42:23 +00001501 beep();
Erik Andersenf0657d32000-04-12 17:49:52 +00001502 }
Erik Andersenc7c634b2000-03-19 05:28:55 +00001503 break;
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001504#endif
Paul Fox3f11b1b2005-08-04 19:04:46 +00001505 case CNTRL('U'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001506 vi_case( case CNTRL('U')|vbit: )
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001507 /* Control-U -- Clear line before cursor */
1508 if (cursor) {
1509 strcpy(command, command + cursor);
1510 redraw(cmdedit_y, len -= cursor);
Erik Andersenc7c634b2000-03-19 05:28:55 +00001511 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001512 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001513 case CNTRL('W'):
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001514 vi_case( case CNTRL('W')|vbit: )
Eric Andersen27bb7902003-12-23 20:24:51 +00001515 /* Control-W -- Remove the last word */
1516 while (cursor > 0 && isspace(command[cursor-1]))
1517 input_backspace();
1518 while (cursor > 0 &&!isspace(command[cursor-1]))
1519 input_backspace();
1520 break;
Denis Vlasenko966ec7c2006-11-01 09:13:26 +00001521#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001522 case 'i'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001523 vi_cmdmode = 0;
1524 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001525 case 'I'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001526 input_backward(cursor);
1527 vi_cmdmode = 0;
1528 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001529 case 'a'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001530 input_forward();
1531 vi_cmdmode = 0;
1532 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001533 case 'A'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001534 input_end();
1535 vi_cmdmode = 0;
1536 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001537 case 'x'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001538 input_delete(1);
1539 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001540 case 'X'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001541 if (cursor > 0) {
1542 input_backward(1);
1543 input_delete(1);
1544 }
1545 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001546 case 'W'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001547 vi_Word_motion(command, 1);
1548 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001549 case 'w'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001550 vi_word_motion(command, 1);
1551 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001552 case 'E'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001553 vi_End_motion(command);
1554 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001555 case 'e'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001556 vi_end_motion(command);
1557 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001558 case 'B'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001559 vi_Back_motion(command);
1560 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001561 case 'b'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001562 vi_back_motion(command);
1563 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001564 case 'C'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001565 vi_cmdmode = 0;
1566 /* fall through */
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001567 case 'D'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001568 goto clear_to_eol;
1569
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001570 case 'c'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001571 vi_cmdmode = 0;
1572 /* fall through */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001573 case 'd'|vbit: {
1574 int nc, sc;
1575 sc = cursor;
1576 prevc = ic;
1577 if (safe_read(0, &c, 1) < 1)
1578 goto prepare_to_die;
1579 if (c == (prevc & 0xff)) {
1580 /* "cc", "dd" */
1581 input_backward(cursor);
1582 goto clear_to_eol;
1583 break;
1584 }
1585 switch (c) {
1586 case 'w':
1587 case 'W':
1588 case 'e':
1589 case 'E':
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001590 switch (c) {
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001591 case 'w': /* "dw", "cw" */
1592 vi_word_motion(command, vi_cmdmode);
Denis Vlasenko92758142006-10-03 19:56:34 +00001593 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001594 case 'W': /* 'dW', 'cW' */
1595 vi_Word_motion(command, vi_cmdmode);
Denis Vlasenko92758142006-10-03 19:56:34 +00001596 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001597 case 'e': /* 'de', 'ce' */
1598 vi_end_motion(command);
1599 input_forward();
Denis Vlasenko92758142006-10-03 19:56:34 +00001600 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001601 case 'E': /* 'dE', 'cE' */
1602 vi_End_motion(command);
1603 input_forward();
Denis Vlasenko92758142006-10-03 19:56:34 +00001604 break;
1605 }
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001606 nc = cursor;
1607 input_backward(cursor - sc);
1608 while (nc-- > cursor)
1609 input_delete(1);
1610 break;
1611 case 'b': /* "db", "cb" */
1612 case 'B': /* implemented as B */
1613 if (c == 'b')
1614 vi_back_motion(command);
1615 else
1616 vi_Back_motion(command);
1617 while (sc-- > cursor)
1618 input_delete(1);
1619 break;
1620 case ' ': /* "d ", "c " */
1621 input_delete(1);
1622 break;
1623 case '$': /* "d$", "c$" */
1624 clear_to_eol:
1625 while (cursor < len)
1626 input_delete(1);
1627 break;
Paul Fox3f11b1b2005-08-04 19:04:46 +00001628 }
1629 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001630 }
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001631 case 'p'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001632 input_forward();
1633 /* fallthrough */
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001634 case 'P'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001635 put();
1636 break;
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001637 case 'r'|vbit:
Paul Fox3f11b1b2005-08-04 19:04:46 +00001638 if (safe_read(0, &c, 1) < 1)
1639 goto prepare_to_die;
1640 if (c == 0)
1641 beep();
1642 else {
1643 *(command + cursor) = c;
1644 putchar(c);
1645 putchar('\b');
1646 }
1647 break;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001648#endif /* FEATURE_COMMAND_EDITING_VI */
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001649
1650 case ESC:
1651
Denis Vlasenko966ec7c2006-11-01 09:13:26 +00001652#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +00001653 if (vi_mode) {
1654 /* ESC: insert mode --> command mode */
1655 vi_cmdmode = 1;
1656 input_backward(1);
1657 break;
1658 }
1659#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001660 /* escape sequence follows */
Eric Andersen7467c8d2001-07-12 20:26:32 +00001661 if (safe_read(0, &c, 1) < 1)
1662 goto prepare_to_die;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001663 /* different vt100 emulations */
1664 if (c == '[' || c == 'O') {
Paul Fox0f2dd9f2006-03-07 20:26:11 +00001665 vi_case( case '['|vbit: )
1666 vi_case( case 'O'|vbit: )
Eric Andersen7467c8d2001-07-12 20:26:32 +00001667 if (safe_read(0, &c, 1) < 1)
1668 goto prepare_to_die;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001669 }
Glenn L McGrath475820c2004-01-22 12:42:23 +00001670 if (c >= '1' && c <= '9') {
1671 unsigned char dummy;
1672
1673 if (safe_read(0, &dummy, 1) < 1)
1674 goto prepare_to_die;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001675 if (dummy != '~')
Glenn L McGrath475820c2004-01-22 12:42:23 +00001676 c = 0;
1677 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001678 switch (c) {
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001679#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenc470f442003-07-28 09:56:35 +00001680 case '\t': /* Alt-Tab */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001681
1682 input_tab(&lastWasTab);
1683 break;
1684#endif
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001685#if MAX_HISTORY > 0
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001686 case 'A':
1687 /* Up Arrow -- Get previous command from history */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001688 if (cur_history > 0) {
1689 get_previous_history();
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001690 goto rewrite_line;
1691 } else {
1692 beep();
1693 }
1694 break;
1695 case 'B':
1696 /* Down Arrow -- Get next command in history */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001697 if (!get_next_history())
Paul Fox3f11b1b2005-08-04 19:04:46 +00001698 break;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001699 /* Rewrite the line with the selected history item */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001700rewrite_line:
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001701 /* change command */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001702 len = strlen(strcpy(command, history[cur_history]));
Paul Fox3f11b1b2005-08-04 19:04:46 +00001703 /* redraw and go to eol (bol, in vi */
Denis Vlasenko966ec7c2006-11-01 09:13:26 +00001704#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +00001705 redraw(cmdedit_y, vi_mode ? 9999:0);
1706#else
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001707 redraw(cmdedit_y, 0);
Paul Fox3f11b1b2005-08-04 19:04:46 +00001708#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001709 break;
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001710#endif
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001711 case 'C':
1712 /* Right Arrow -- Move forward one character */
1713 input_forward();
1714 break;
1715 case 'D':
1716 /* Left Arrow -- Move back one character */
1717 input_backward(1);
1718 break;
1719 case '3':
1720 /* Delete */
Paul Fox3f11b1b2005-08-04 19:04:46 +00001721 input_delete(0);
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001722 break;
1723 case '1':
1724 case 'H':
Glenn L McGrath7fc504c2004-02-22 11:13:28 +00001725 /* <Home> */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001726 input_backward(cursor);
1727 break;
1728 case '4':
1729 case 'F':
Glenn L McGrath7fc504c2004-02-22 11:13:28 +00001730 /* <End> */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001731 input_end();
1732 break;
1733 default:
Glenn L McGrath475820c2004-01-22 12:42:23 +00001734 c = 0;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001735 beep();
1736 }
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001737 break;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001738
Eric Andersenc470f442003-07-28 09:56:35 +00001739 default: /* If it's regular input, do the normal thing */
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001740#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001741 /* Control-V -- Add non-printable symbol */
Paul Fox3f11b1b2005-08-04 19:04:46 +00001742 if (c == CNTRL('V')) {
Eric Andersen7467c8d2001-07-12 20:26:32 +00001743 if (safe_read(0, &c, 1) < 1)
1744 goto prepare_to_die;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001745 if (c == 0) {
1746 beep();
1747 break;
1748 }
1749 } else
1750#endif
Paul Fox3f11b1b2005-08-04 19:04:46 +00001751 {
Denis Vlasenko966ec7c2006-11-01 09:13:26 +00001752#if ENABLE_FEATURE_COMMAND_EDITING_VI
Paul Fox3f11b1b2005-08-04 19:04:46 +00001753 if (vi_cmdmode) /* don't self-insert */
1754 break;
1755#endif
1756 if (!Isprint(c)) /* Skip non-printable characters */
1757 break;
1758 }
Erik Andersenc7c634b2000-03-19 05:28:55 +00001759
Eric Andersenc470f442003-07-28 09:56:35 +00001760 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
Erik Andersenc7c634b2000-03-19 05:28:55 +00001761 break;
1762
1763 len++;
1764
Eric Andersenc470f442003-07-28 09:56:35 +00001765 if (cursor == (len - 1)) { /* Append if at the end of the line */
Erik Andersenf0657d32000-04-12 17:49:52 +00001766 *(command + cursor) = c;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001767 *(command + cursor + 1) = 0;
1768 cmdedit_set_out_char(0);
Eric Andersenc470f442003-07-28 09:56:35 +00001769 } else { /* Insert otherwise */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001770 int sc = cursor;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001771
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001772 memmove(command + sc + 1, command + sc, len - sc);
1773 *(command + sc) = c;
1774 sc++;
Mark Whitley4e338752001-01-26 20:42:23 +00001775 /* rewrite from cursor */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001776 input_end();
Mark Whitley4e338752001-01-26 20:42:23 +00001777 /* to prev x pos + 1 */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001778 input_backward(cursor - sc);
Erik Andersenc7c634b2000-03-19 05:28:55 +00001779 }
1780
Erik Andersenc7c634b2000-03-19 05:28:55 +00001781 break;
Erik Andersen13456d12000-03-16 08:09:57 +00001782 }
Eric Andersenc470f442003-07-28 09:56:35 +00001783 if (break_out) /* Enter is the command terminator, no more input. */
Erik Andersenc7c634b2000-03-19 05:28:55 +00001784 break;
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001785
1786 if (c != '\t')
1787 lastWasTab = FALSE;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001788 }
1789
Glenn L McGrath78b0e372001-06-26 02:06:08 +00001790 setTermSettings(0, (void *) &initial_settings);
Mark Whitley4e338752001-01-26 20:42:23 +00001791 handlers_sets &= ~SET_RESET_TERM;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001792
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001793#if MAX_HISTORY > 0
Erik Andersenc7c634b2000-03-19 05:28:55 +00001794 /* Handle command history log */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001795 /* cleanup may be saved current command line */
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001796 if (len > 0) { /* no put empty line */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001797 int i = n_history;
Glenn L McGrath7fc504c2004-02-22 11:13:28 +00001798
1799 free(history[MAX_HISTORY]);
1800 history[MAX_HISTORY] = 0;
Erik Andersenc7c634b2000-03-19 05:28:55 +00001801 /* After max history, remove the oldest command */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001802 if (i >= MAX_HISTORY) {
1803 free(history[0]);
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001804 for(i = 0; i < MAX_HISTORY-1; i++)
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001805 history[i] = history[i+1];
Erik Andersen13456d12000-03-16 08:09:57 +00001806 }
Rob Landleyd921b2e2006-08-03 15:41:12 +00001807 history[i++] = xstrdup(command);
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001808 cur_history = i;
1809 n_history = i;
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001810#if ENABLE_FEATURE_SH_FANCY_PROMPT
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001811 num_ok_lines++;
1812#endif
Erik Andersen6273f652000-03-17 01:12:41 +00001813 }
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001814#else /* MAX_HISTORY == 0 */
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001815#if ENABLE_FEATURE_SH_FANCY_PROMPT
Glenn L McGrath16e45d72004-02-04 08:24:39 +00001816 if (len > 0) { /* no put empty line */
Glenn L McGrath062c74f2002-11-27 09:29:49 +00001817 num_ok_lines++;
1818 }
1819#endif
Denis Vlasenko9d4533e2006-11-02 22:09:37 +00001820#endif /* MAX_HISTORY > 0 */
Eric Andersen27bb7902003-12-23 20:24:51 +00001821 if (break_out > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00001822 command[len++] = '\n'; /* set '\n' */
1823 command[len] = 0;
Eric Andersen044228d2001-07-17 01:12:36 +00001824 }
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001825#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenc470f442003-07-28 09:56:35 +00001826 input_tab(0); /* strong free */
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001827#endif
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001828#if ENABLE_FEATURE_SH_FANCY_PROMPT
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001829 free(cmdedit_prompt);
1830#endif
Eric Andersen501c88b2000-07-28 15:14:45 +00001831 cmdedit_reset_term();
Eric Andersen044228d2001-07-17 01:12:36 +00001832 return len;
Eric Andersen501c88b2000-07-28 15:14:45 +00001833}
1834
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001835#endif /* FEATURE_COMMAND_EDITING */
Eric Andersen501c88b2000-07-28 15:14:45 +00001836
1837
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001838#ifdef TEST
1839
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001840const char *applet_name = "debug stuff usage";
Eric Andersene5dfced2001-04-09 22:48:12 +00001841
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001842#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersenf9ff8a72001-03-15 20:51:09 +00001843#include <locale.h>
1844#endif
1845
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001846int main(int argc, char **argv)
1847{
1848 char buff[BUFSIZ];
1849 char *prompt =
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001850#if ENABLE_FEATURE_SH_FANCY_PROMPT
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001851 "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
1852 "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
1853 "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001854#else
1855 "% ";
1856#endif
1857
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001858#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
Eric Andersenf9ff8a72001-03-15 20:51:09 +00001859 setlocale(LC_ALL, "");
1860#endif
Denis Vlasenko7f1dc212006-12-19 01:10:25 +00001861 while (1) {
Eric Andersenb3d6e2d2001-03-13 22:57:56 +00001862 int l;
Eric Andersen27bb7902003-12-23 20:24:51 +00001863 l = cmdedit_read_input(prompt, buff);
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001864 if (l <= 0 || buff[l-1] != '\n')
Eric Andersen27bb7902003-12-23 20:24:51 +00001865 break;
Denis Vlasenko0a8a7742006-12-21 22:27:10 +00001866 buff[l-1] = 0;
1867 printf("*** cmdedit_read_input() returned line =%s=\n", buff);
Eric Andersen7467c8d2001-07-12 20:26:32 +00001868 }
Eric Andersen27bb7902003-12-23 20:24:51 +00001869 printf("*** cmdedit_read_input() detect ^D\n");
Eric Andersen5f2c79d2001-02-16 18:36:04 +00001870 return 0;
1871}
1872
Eric Andersenc470f442003-07-28 09:56:35 +00001873#endif /* TEST */