aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-01-22 07:21:38 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-01-22 07:21:38 +0000
commit145366b9719857c48f9a7ada7d7e0ff8edfbd0de (patch)
tree2f115293c25e7ee9307f268ec198e2cf486ff070
parent5c7a4f79ea56b11e0e9927dc51268d7049aadf2e (diff)
downloadbusybox-w32-145366b9719857c48f9a7ada7d7e0ff8edfbd0de.tar.gz
busybox-w32-145366b9719857c48f9a7ada7d7e0ff8edfbd0de.tar.bz2
busybox-w32-145366b9719857c48f9a7ada7d7e0ff8edfbd0de.zip
Convert cmdedit into more generic line input facility
(make history and completion optional at runtime). Use it for fdisk, as an example. Some unrelated fixes in fdisk are also here. git-svn-id: svn://busybox.net/trunk/busybox@17446 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--include/libbb.h36
-rw-r--r--shell/Kbuild10
-rw-r--r--shell/ash.c106
-rw-r--r--shell/cmdedit.c316
-rw-r--r--shell/cmdedit.h21
-rw-r--r--shell/hush.c13
-rw-r--r--shell/lash.c14
-rw-r--r--shell/msh.c26
-rw-r--r--util-linux/fdisk.c309
-rw-r--r--util-linux/fdisk_osf.c46
10 files changed, 459 insertions, 438 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 0b066d1bd..f990b0ebd 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -583,6 +583,42 @@ extern unsigned long long bb_makedev(unsigned int major, unsigned int minor);
583#endif 583#endif
584 584
585 585
586#if ENABLE_FEATURE_COMMAND_EDITING
587/* It's NOT just ENABLEd or disabled. It's a number: */
588#ifdef CONFIG_FEATURE_COMMAND_HISTORY
589#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
590#else
591#define MAX_HISTORY 0
592#endif
593struct line_input_t {
594 int flags;
595 const char *path_lookup;
596#if MAX_HISTORY
597 int cnt_history;
598 int cur_history;
599 USE_FEATURE_COMMAND_SAVEHISTORY(const char *hist_file;)
600 char *history[MAX_HISTORY + 1];
601#endif
602};
603enum {
604 DO_HISTORY = 1 * (MAX_HISTORY > 0),
605 SAVE_HISTORY = 2 * (MAX_HISTORY > 0) * ENABLE_FEATURE_COMMAND_SAVEHISTORY,
606 TAB_COMPLETION = 4 * ENABLE_FEATURE_COMMAND_TAB_COMPLETION,
607 USERNAME_COMPLETION = 8 * ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION,
608 VI_MODE = 0x10 * ENABLE_FEATURE_COMMAND_EDITING_VI,
609 WITH_PATH_LOOKUP = 0x20,
610 FOR_SHELL = DO_HISTORY | SAVE_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
611};
612typedef struct line_input_t line_input_t;
613line_input_t *new_line_input_t(int flags);
614int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state);
615#else
616int read_line_input(const char* prompt, char* command, int maxsize);
617#define read_line_input(prompt, command, maxsize, state) \
618 read_line_input(prompt, command, maxsize)
619#endif
620
621
586#ifndef COMM_LEN 622#ifndef COMM_LEN
587#ifdef TASK_COMM_LEN 623#ifdef TASK_COMM_LEN
588enum { COMM_LEN = TASK_COMM_LEN }; 624enum { COMM_LEN = TASK_COMM_LEN };
diff --git a/shell/Kbuild b/shell/Kbuild
index eb0199ee2..9c60698f7 100644
--- a/shell/Kbuild
+++ b/shell/Kbuild
@@ -5,8 +5,8 @@
5# Licensed under the GPL v2, see the file LICENSE in this tarball. 5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6 6
7lib-y:= 7lib-y:=
8lib-$(CONFIG_ASH) += ash.o 8lib-y += cmdedit.o
9lib-$(CONFIG_HUSH) += hush.o 9lib-$(CONFIG_ASH) += ash.o
10lib-$(CONFIG_LASH) += lash.o 10lib-$(CONFIG_HUSH) += hush.o
11lib-$(CONFIG_MSH) += msh.o 11lib-$(CONFIG_LASH) += lash.o
12lib-$(CONFIG_FEATURE_COMMAND_EDITING) += cmdedit.o 12lib-$(CONFIG_MSH) += msh.o
diff --git a/shell/ash.c b/shell/ash.c
index 2db3302c7..8afdf3d21 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -92,7 +92,6 @@
92#include <termios.h> 92#include <termios.h>
93#endif 93#endif
94 94
95#include "cmdedit.h"
96 95
97#ifdef __GLIBC__ 96#ifdef __GLIBC__
98/* glibc sucks */ 97/* glibc sucks */
@@ -1238,7 +1237,7 @@ static int fgcmd(int, char **);
1238static int getoptscmd(int, char **); 1237static int getoptscmd(int, char **);
1239#endif 1238#endif
1240static int hashcmd(int, char **); 1239static int hashcmd(int, char **);
1241#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1240#if !ENABLE_FEATURE_SH_EXTRA_QUIET
1242static int helpcmd(int argc, char **argv); 1241static int helpcmd(int argc, char **argv);
1243#endif 1242#endif
1244#if JOBS 1243#if JOBS
@@ -1347,7 +1346,7 @@ static const struct builtincmd builtincmd[] = {
1347 { BUILTIN_REGULAR "getopts", getoptscmd }, 1346 { BUILTIN_REGULAR "getopts", getoptscmd },
1348#endif 1347#endif
1349 { BUILTIN_NOSPEC "hash", hashcmd }, 1348 { BUILTIN_NOSPEC "hash", hashcmd },
1350#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1349#if !ENABLE_FEATURE_SH_EXTRA_QUIET
1351 { BUILTIN_NOSPEC "help", helpcmd }, 1350 { BUILTIN_NOSPEC "help", helpcmd },
1352#endif 1351#endif
1353#if JOBS 1352#if JOBS
@@ -1529,7 +1528,7 @@ static struct var varinit[] = {
1529 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1528 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1530 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1529 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1531#endif 1530#endif
1532#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 1531#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
1533 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1534#endif 1533#endif
1535}; 1534};
@@ -1934,10 +1933,6 @@ struct shparam {
1934#define debug optlist[15] 1933#define debug optlist[15]
1935#endif 1934#endif
1936 1935
1937#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1938#define setvimode(on) viflag = 0 /* forcibly keep the option off */
1939#endif
1940
1941/* options.c */ 1936/* options.c */
1942 1937
1943 1938
@@ -3718,7 +3713,7 @@ shellexec(char **argv, const char *path, int idx)
3718 clearredir(1); 3713 clearredir(1);
3719 envp = environment(); 3714 envp = environment();
3720 if (strchr(argv[0], '/') || is_safe_applet(argv[0]) 3715 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
3721#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3716#if ENABLE_FEATURE_SH_STANDALONE_SHELL
3722 || find_applet_by_name(argv[0]) 3717 || find_applet_by_name(argv[0])
3723#endif 3718#endif
3724 ) { 3719 ) {
@@ -3775,7 +3770,7 @@ tryexec(char *cmd, char **argv, char **envp)
3775 applet_name = cmd; 3770 applet_name = cmd;
3776 exit(a->main(argc, argv)); 3771 exit(a->main(argc, argv));
3777 } 3772 }
3778#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3773#if ENABLE_FEATURE_SH_STANDALONE_SHELL
3779 if (find_applet_by_name(cmd) != NULL) { 3774 if (find_applet_by_name(cmd) != NULL) {
3780 /* re-exec ourselves with the new arguments */ 3775 /* re-exec ourselves with the new arguments */
3781 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp); 3776 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
@@ -3949,7 +3944,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
3949 return; 3944 return;
3950 } 3945 }
3951 3946
3952#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3947#if ENABLE_FEATURE_SH_STANDALONE_SHELL
3953 if (find_applet_by_name(name)) { 3948 if (find_applet_by_name(name)) {
3954 entry->cmdtype = CMDNORMAL; 3949 entry->cmdtype = CMDNORMAL;
3955 entry->u.index = -1; 3950 entry->u.index = -1;
@@ -6045,21 +6040,18 @@ static char * pfgets(char *line, int len)
6045} 6040}
6046 6041
6047 6042
6048 6043#if ENABLE_FEATURE_COMMAND_EDITING
6049#ifdef CONFIG_FEATURE_COMMAND_EDITING 6044static line_input_t *line_input_state;
6050#ifdef CONFIG_ASH_EXPAND_PRMT 6045//static SKIP_ASH_EXPAND_PRMT(const) char *cmdedit_prompt;
6051static char *cmdedit_prompt;
6052#else
6053static const char *cmdedit_prompt; 6046static const char *cmdedit_prompt;
6054#endif
6055static void putprompt(const char *s) 6047static void putprompt(const char *s)
6056{ 6048{
6057#ifdef CONFIG_ASH_EXPAND_PRMT 6049 if (ENABLE_ASH_EXPAND_PRMT) {
6058 free(cmdedit_prompt); 6050 free((char*)cmdedit_prompt);
6059 cmdedit_prompt = xstrdup(s); 6051 cmdedit_prompt = xstrdup(s);
6060#else 6052 return;
6053 }
6061 cmdedit_prompt = s; 6054 cmdedit_prompt = s;
6062#endif
6063} 6055}
6064#else 6056#else
6065static void putprompt(const char *s) 6057static void putprompt(const char *s)
@@ -6068,6 +6060,16 @@ static void putprompt(const char *s)
6068} 6060}
6069#endif 6061#endif
6070 6062
6063#if ENABLE_FEATURE_COMMAND_EDITING_VI
6064#define setvimode(on) do { \
6065 if (on) line_input_state->flags |= VI_MODE; \
6066 else line_input_state->flags &= ~VI_MODE; \
6067} while (0)
6068#else
6069#define setvimode(on) viflag = 0 /* forcibly keep the option off */
6070#endif
6071
6072
6071static int preadfd(void) 6073static int preadfd(void)
6072{ 6074{
6073 int nr; 6075 int nr;
@@ -6075,25 +6077,25 @@ static int preadfd(void)
6075 parsenextc = buf; 6077 parsenextc = buf;
6076 6078
6077retry: 6079retry:
6078#ifdef CONFIG_FEATURE_COMMAND_EDITING 6080#if ENABLE_FEATURE_COMMAND_EDITING
6079 if (!iflag || parsefile->fd) 6081 if (!iflag || parsefile->fd)
6080 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6082 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6081 else { 6083 else {
6082#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION 6084#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
6083 cmdedit_path_lookup = pathval(); 6085 line_input_state->path_lookup = pathval();
6084#endif 6086#endif
6085 nr = cmdedit_read_input((char *) cmdedit_prompt, buf); 6087 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
6086 if(nr == 0) { 6088 if (nr == 0) {
6087 /* Ctrl+C presend */ 6089 /* Ctrl+C pressed */
6088 if(trap[SIGINT]) { 6090 if (trap[SIGINT]) {
6089 buf[0] = '\n'; 6091 buf[0] = '\n';
6090 buf[1] = 0; 6092 buf[1] = '\0';
6091 raise(SIGINT); 6093 raise(SIGINT);
6092 return 1; 6094 return 1;
6093 } 6095 }
6094 goto retry; 6096 goto retry;
6095 } 6097 }
6096 if(nr < 0 && errno == 0) { 6098 if (nr < 0 && errno == 0) {
6097 /* Ctrl+D presend */ 6099 /* Ctrl+D presend */
6098 nr = 0; 6100 nr = 0;
6099 } 6101 }
@@ -7913,6 +7915,10 @@ ash_main(int argc, char **argv)
7913#if PROFILE 7915#if PROFILE
7914 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7916 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7915#endif 7917#endif
7918
7919#if ENABLE_FEATURE_COMMAND_EDITING
7920 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
7921#endif
7916 state = 0; 7922 state = 0;
7917 if (setjmp(jmploc.loc)) { 7923 if (setjmp(jmploc.loc)) {
7918 int e; 7924 int e;
@@ -7954,11 +7960,11 @@ ash_main(int argc, char **argv)
7954 init(); 7960 init();
7955 setstackmark(&smark); 7961 setstackmark(&smark);
7956 procargs(argc, argv); 7962 procargs(argc, argv);
7957#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7963#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
7958 if ( iflag ) { 7964 if (iflag) {
7959 const char *hp = lookupvar("HISTFILE"); 7965 const char *hp = lookupvar("HISTFILE");
7960 7966
7961 if(hp == NULL ) { 7967 if (hp == NULL) {
7962 hp = lookupvar("HOME"); 7968 hp = lookupvar("HOME");
7963 if(hp != NULL) { 7969 if(hp != NULL) {
7964 char *defhp = concat_path_file(hp, ".ash_history"); 7970 char *defhp = concat_path_file(hp, ".ash_history");
@@ -7995,15 +8001,15 @@ state3:
7995 evalstring(minusc, 0); 8001 evalstring(minusc, 0);
7996 8002
7997 if (sflag || minusc == NULL) { 8003 if (sflag || minusc == NULL) {
7998#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 8004#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
7999 if ( iflag ) { 8005 if ( iflag ) {
8000 const char *hp = lookupvar("HISTFILE"); 8006 const char *hp = lookupvar("HISTFILE");
8001 8007
8002 if(hp != NULL ) 8008 if (hp != NULL)
8003 load_history ( hp ); 8009 line_input_state->hist_file = hp;
8004 } 8010 }
8005#endif 8011#endif
8006state4: /* XXX ??? - why isn't this before the "if" statement */ 8012 state4: /* XXX ??? - why isn't this before the "if" statement */
8007 cmdloop(1); 8013 cmdloop(1);
8008 } 8014 }
8009#if PROFILE 8015#if PROFILE
@@ -11880,7 +11886,7 @@ setinteractive(int on)
11880 setsignal(SIGINT); 11886 setsignal(SIGINT);
11881 setsignal(SIGQUIT); 11887 setsignal(SIGQUIT);
11882 setsignal(SIGTERM); 11888 setsignal(SIGTERM);
11883#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11889#if !ENABLE_FEATURE_SH_EXTRA_QUIET
11884 if(is_interactive > 1) { 11890 if(is_interactive > 1) {
11885 /* Looks like they want an interactive shell */ 11891 /* Looks like they want an interactive shell */
11886 static int do_banner; 11892 static int do_banner;
@@ -11897,7 +11903,7 @@ setinteractive(int on)
11897} 11903}
11898 11904
11899 11905
11900#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11906#if !ENABLE_FEATURE_SH_EXTRA_QUIET
11901/*** List the available builtins ***/ 11907/*** List the available builtins ***/
11902 11908
11903static int helpcmd(int argc, char **argv) 11909static int helpcmd(int argc, char **argv)
@@ -11913,7 +11919,7 @@ static int helpcmd(int argc, char **argv)
11913 col = 0; 11919 col = 0;
11914 } 11920 }
11915 } 11921 }
11916#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 11922#if ENABLE_FEATURE_SH_STANDALONE_SHELL
11917 for (i = 0; i < NUM_APPLETS; i++) { 11923 for (i = 0; i < NUM_APPLETS; i++) {
11918 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11924 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11919 if (col > 60) { 11925 if (col > 60) {
@@ -11945,7 +11951,7 @@ exitshell(void)
11945/* dash bug: it just does _exit(exitstatus) here 11951/* dash bug: it just does _exit(exitstatus) here
11946 * but we have to do setjobctl(0) first! 11952 * but we have to do setjobctl(0) first!
11947 * (bug is still not fixed in dash-0.5.3 - if you run dash 11953 * (bug is still not fixed in dash-0.5.3 - if you run dash
11948 * under Midnight Commander, on exit MC is backgrounded) */ 11954 * under Midnight Commander, on exit from dash MC is backgrounded) */
11949 status = exitstatus; 11955 status = exitstatus;
11950 goto out; 11956 goto out;
11951 } 11957 }
@@ -11955,14 +11961,6 @@ exitshell(void)
11955 evalstring(p, 0); 11961 evalstring(p, 0);
11956 } 11962 }
11957 flushall(); 11963 flushall();
11958#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11959 if (iflag && rootshell) {
11960 const char *hp = lookupvar("HISTFILE");
11961
11962 if (hp != NULL)
11963 save_history(hp);
11964 }
11965#endif
11966out: 11964out:
11967 setjobctl(0); 11965 setjobctl(0);
11968 _exit(status); 11966 _exit(status);
@@ -13491,7 +13489,7 @@ static const char op_tokens[] = {
13491#define endexpression &op_tokens[sizeof(op_tokens)-7] 13489#define endexpression &op_tokens[sizeof(op_tokens)-7]
13492 13490
13493 13491
13494static arith_t arith (const char *expr, int *perrcode) 13492static arith_t arith(const char *expr, int *perrcode)
13495{ 13493{
13496 char arithval; /* Current character under analysis */ 13494 char arithval; /* Current character under analysis */
13497 operator lasttok, op; 13495 operator lasttok, op;
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index a1432af15..554a4ebec 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -30,7 +30,6 @@
30 30
31#include <sys/ioctl.h> 31#include <sys/ioctl.h>
32#include "busybox.h" 32#include "busybox.h"
33#include "cmdedit.h"
34 33
35 34
36/* FIXME: obsolete CONFIG item? */ 35/* FIXME: obsolete CONFIG item? */
@@ -51,7 +50,6 @@
51/* Entire file (except TESTing part) sits inside this #if */ 50/* Entire file (except TESTing part) sits inside this #if */
52#if ENABLE_FEATURE_COMMAND_EDITING 51#if ENABLE_FEATURE_COMMAND_EDITING
53 52
54
55#if ENABLE_LOCALE_SUPPORT 53#if ENABLE_LOCALE_SUPPORT
56#define Isprint(c) isprint(c) 54#define Isprint(c) isprint(c)
57#else 55#else
@@ -61,29 +59,21 @@
61#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ 59#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
62(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) 60(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT)
63 61
64/* Maximum length of command line history */
65#if !ENABLE_FEATURE_COMMAND_HISTORY
66#define MAX_HISTORY 15
67#else
68#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
69#endif
70 62
63static line_input_t *state;
71 64
72/* Current termios and the previous termios before starting sh */
73static struct termios initial_settings, new_settings; 65static struct termios initial_settings, new_settings;
74 66
75static 67static volatile unsigned cmdedit_termw = 80; /* actual terminal width */
76volatile unsigned cmdedit_termw = 80; /* actual terminal width */
77
78 68
79static int cmdedit_x; /* real x terminal position */ 69static int cmdedit_x; /* real x terminal position */
80static int cmdedit_y; /* pseudoreal y terminal position */ 70static int cmdedit_y; /* pseudoreal y terminal position */
81static int cmdedit_prmt_len; /* length of prompt (without colors etc) */ 71static int cmdedit_prmt_len; /* length of prompt (without colors etc) */
82 72
83static int cursor; 73static unsigned cursor;
84static int len; 74static unsigned command_len;
85static char *command_ps; 75static char *command_ps;
86static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; 76static const char *cmdedit_prompt;
87 77
88#if ENABLE_FEATURE_SH_FANCY_PROMPT 78#if ENABLE_FEATURE_SH_FANCY_PROMPT
89static char *hostname_buf; 79static char *hostname_buf;
@@ -142,7 +132,7 @@ static void cmdedit_set_out_char(int next_char)
142/* Move to end of line (by printing all chars till the end) */ 132/* Move to end of line (by printing all chars till the end) */
143static void input_end(void) 133static void input_end(void)
144{ 134{
145 while (cursor < len) 135 while (cursor < command_len)
146 cmdedit_set_out_char(' '); 136 cmdedit_set_out_char(' ');
147} 137}
148 138
@@ -200,7 +190,7 @@ static void input_backward(unsigned num)
200static void put_prompt(void) 190static void put_prompt(void)
201{ 191{
202 out1str(cmdedit_prompt); 192 out1str(cmdedit_prompt);
203 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ 193 cmdedit_x = cmdedit_prmt_len;
204 cursor = 0; 194 cursor = 0;
205// Huh? what if cmdedit_prmt_len >= width? 195// Huh? what if cmdedit_prmt_len >= width?
206 cmdedit_y = 0; /* new quasireal y */ 196 cmdedit_y = 0; /* new quasireal y */
@@ -231,7 +221,7 @@ static void input_delete(int save)
231{ 221{
232 int j = cursor; 222 int j = cursor;
233 223
234 if (j == len) 224 if (j == command_len)
235 return; 225 return;
236 226
237#if ENABLE_FEATURE_COMMAND_EDITING_VI 227#if ENABLE_FEATURE_COMMAND_EDITING_VI
@@ -249,7 +239,7 @@ static void input_delete(int save)
249#endif 239#endif
250 240
251 strcpy(command_ps + j, command_ps + j + 1); 241 strcpy(command_ps + j, command_ps + j + 1);
252 len--; 242 command_len--;
253 input_end(); /* rewrite new line */ 243 input_end(); /* rewrite new line */
254 cmdedit_set_out_char(' '); /* erase char */ 244 cmdedit_set_out_char(' '); /* erase char */
255 input_backward(cursor - j); /* back to old pos cursor */ 245 input_backward(cursor - j); /* back to old pos cursor */
@@ -285,7 +275,7 @@ static void input_backspace(void)
285/* Move forward one character */ 275/* Move forward one character */
286static void input_forward(void) 276static void input_forward(void)
287{ 277{
288 if (cursor < len) 278 if (cursor < command_len)
289 cmdedit_set_out_char(command_ps[cursor + 1]); 279 cmdedit_set_out_char(command_ps[cursor + 1]);
290} 280}
291 281
@@ -372,54 +362,50 @@ enum {
372 FIND_FILE_ONLY = 2, 362 FIND_FILE_ONLY = 2,
373}; 363};
374 364
375#if ENABLE_ASH
376const char *cmdedit_path_lookup;
377#endif
378static int path_parse(char ***p, int flags) 365static int path_parse(char ***p, int flags)
379{ 366{
380 int npth; 367 int npth;
381 const char *tmp; 368 const char *tmp;
382#if ENABLE_ASH 369 const char *pth;
383 const char *pth = cmdedit_path_lookup; 370 char **res;
384#else
385 const char *pth = getenv("PATH")
386#endif
387 371
388 /* if not setenv PATH variable, to search cur dir "." */ 372 /* if not setenv PATH variable, to search cur dir "." */
389 if (flags != FIND_EXE_ONLY) 373 if (flags != FIND_EXE_ONLY)
390 return 1; 374 return 1;
375
376 if (state->flags & WITH_PATH_LOOKUP)
377 pth = state->path_lookup;
378 else
379 pth = getenv("PATH");
391 /* PATH=<empty> or PATH=:<empty> */ 380 /* PATH=<empty> or PATH=:<empty> */
392 if (!pth || !pth[0] || LONE_CHAR(pth, ':')) 381 if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
393 return 1; 382 return 1;
394 383
395 tmp = pth; 384 tmp = pth;
396 npth = 0; 385 npth = 1; /* path component count */
397
398 while (1) { 386 while (1) {
399 npth++; /* count words is + 1 count ':' */
400 tmp = strchr(tmp, ':'); 387 tmp = strchr(tmp, ':');
401 if (!tmp) 388 if (!tmp)
402 break; 389 break;
403 if (*++tmp == '\0') 390 if (*++tmp == '\0')
404 break; /* :<empty> */ 391 break; /* :<empty> */
392 npth++;
405 } 393 }
406 394
407 *p = xmalloc(npth * sizeof(char *)); 395 res = xmalloc(npth * sizeof(char*));
408 396 res[0] = xstrdup(pth);
409 tmp = pth; 397 tmp = pth;
410 (*p)[0] = xstrdup(tmp); 398 npth = 1;
411 npth = 1; /* count words is + 1 count ':' */
412
413 while (1) { 399 while (1) {
414 tmp = strchr(tmp, ':'); 400 tmp = strchr(tmp, ':');
415 if (!tmp) 401 if (!tmp)
416 break; 402 break;
417 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ 403 *tmp++ = '\0'; /* ':' -> '\0' */
418 if (*++tmp == 0) 404 if (*tmp == '\0')
419 break; /* :<empty> */ 405 break; /* :<empty> */
420 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ 406 res[npth++] = tmp;
421 } 407 }
422 408 *p = res;
423 return npth; 409 return npth;
424} 410}
425 411
@@ -742,6 +728,9 @@ static int match_compare(const void *a, const void *b)
742/* Do TAB completion */ 728/* Do TAB completion */
743static void input_tab(int *lastWasTab) 729static void input_tab(int *lastWasTab)
744{ 730{
731 if (!(state->flags & TAB_COMPLETION))
732 return;
733
745 if (!*lastWasTab) { 734 if (!*lastWasTab) {
746 char *tmp, *tmp1; 735 char *tmp, *tmp1;
747 int len_found; 736 int len_found;
@@ -764,13 +753,13 @@ static void input_tab(int *lastWasTab)
764#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 753#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
765 /* If the word starts with `~' and there is no slash in the word, 754 /* If the word starts with `~' and there is no slash in the word,
766 * then try completing this word as a username. */ 755 * then try completing this word as a username. */
767 756 if (state->flags & USERNAME_COMPLETION)
768 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) 757 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
769 username_tab_completion(matchBuf, NULL); 758 username_tab_completion(matchBuf, NULL);
770 if (!matches)
771#endif 759#endif
772 /* Try to match any executable in our path and everything 760 /* Try to match any executable in our path and everything
773 * in the current working directory */ 761 * in the current working directory */
762 if (!matches)
774 exe_n_cwd_tab_completion(matchBuf, find_type); 763 exe_n_cwd_tab_completion(matchBuf, find_type);
775 /* Sort, then remove any duplicates found */ 764 /* Sort, then remove any duplicates found */
776 if (matches) { 765 if (matches) {
@@ -855,51 +844,48 @@ static void input_tab(int *lastWasTab)
855 } 844 }
856} 845}
857 846
847#else
848#define input_tab(a) ((void)0)
858#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 849#endif /* FEATURE_COMMAND_TAB_COMPLETION */
859 850
860 851
861#if MAX_HISTORY > 0 852#if MAX_HISTORY > 0
862 853
863static char *history[MAX_HISTORY+1]; /* history + current */ 854/* state->flags is already checked to be nonzero */
864/* saved history lines */
865static int n_history;
866/* current pointer to history line */
867static int cur_history;
868
869static void get_previous_history(void) 855static void get_previous_history(void)
870{ 856{
871 if (command_ps[0] != '\0' || history[cur_history] == NULL) { 857 if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) {
872 free(history[cur_history]); 858 free(state->history[state->cur_history]);
873 history[cur_history] = xstrdup(command_ps); 859 state->history[state->cur_history] = xstrdup(command_ps);
874 } 860 }
875 cur_history--; 861 state->cur_history--;
876} 862}
877 863
878static int get_next_history(void) 864static int get_next_history(void)
879{ 865{
880 int ch = cur_history; 866 if (state->flags & DO_HISTORY) {
881 867 int ch = state->cur_history;
882 if (ch < n_history) { 868 if (ch < state->cnt_history) {
883 get_previous_history(); /* save the current history line */ 869 get_previous_history(); /* save the current history line */
884 cur_history = ch + 1; 870 state->cur_history = ch + 1;
885 return cur_history; 871 return state->cur_history;
886 } else { 872 }
887 beep();
888 return 0;
889 } 873 }
874 beep();
875 return 0;
890} 876}
891 877
892#if ENABLE_FEATURE_COMMAND_SAVEHISTORY 878#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
879/* state->flags is already checked to be nonzero */
893void load_history(const char *fromfile) 880void load_history(const char *fromfile)
894{ 881{
895 FILE *fp; 882 FILE *fp;
896 int hi; 883 int hi;
897 884
898 /* cleanup old */ 885 /* cleanup old */
899 886 for (hi = state->cnt_history; hi > 0;) {
900 for (hi = n_history; hi > 0;) {
901 hi--; 887 hi--;
902 free(history[hi]); 888 free(state->history[hi]);
903 } 889 }
904 890
905 fp = fopen(fromfile, "r"); 891 fp = fopen(fromfile, "r");
@@ -917,29 +903,62 @@ void load_history(const char *fromfile)
917 free(hl); 903 free(hl);
918 continue; 904 continue;
919 } 905 }
920 history[hi++] = hl; 906 state->history[hi++] = hl;
921 } 907 }
922 fclose(fp); 908 fclose(fp);
923 } 909 }
924 cur_history = n_history = hi; 910 state->cur_history = state->cnt_history = hi;
925} 911}
926 912
913/* state->flags is already checked to be nonzero */
927void save_history(const char *tofile) 914void save_history(const char *tofile)
928{ 915{
929 FILE *fp = fopen(tofile, "w"); 916 FILE *fp;
930 917
918 fp = fopen(tofile, "w");
931 if (fp) { 919 if (fp) {
932 int i; 920 int i;
933 921
934 for (i = 0; i < n_history; i++) { 922 for (i = 0; i < state->cnt_history; i++) {
935 fprintf(fp, "%s\n", history[i]); 923 fprintf(fp, "%s\n", state->history[i]);
936 } 924 }
937 fclose(fp); 925 fclose(fp);
938 } 926 }
939} 927}
928#else
929#define load_history(a) ((void)0)
930#define save_history(a) ((void)0)
940#endif /* FEATURE_COMMAND_SAVEHISTORY */ 931#endif /* FEATURE_COMMAND_SAVEHISTORY */
941 932
942#endif /* MAX_HISTORY > 0 */ 933static void remember_in_history(const char *str)
934{
935 int i;
936
937 if (!(state->flags & DO_HISTORY))
938 return;
939
940 i = state->cnt_history;
941 free(state->history[MAX_HISTORY]);
942 state->history[MAX_HISTORY] = NULL;
943 /* After max history, remove the oldest command */
944 if (i >= MAX_HISTORY) {
945 free(state->history[0]);
946 for (i = 0; i < MAX_HISTORY-1; i++)
947 state->history[i] = state->history[i+1];
948 }
949// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
950// (i.e. do not save dups?)
951 state->history[i++] = xstrdup(str);
952 state->cur_history = i;
953 state->cnt_history = i;
954 if (state->flags & SAVE_HISTORY)
955 save_history(state->hist_file);
956 USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;)
957}
958
959#else /* MAX_HISTORY == 0 */
960#define remember_in_history(a) ((void)0)
961#endif /* MAX_HISTORY */
943 962
944 963
945/* 964/*
@@ -960,13 +979,6 @@ void save_history(const char *tofile)
960 */ 979 */
961 980
962#if ENABLE_FEATURE_COMMAND_EDITING_VI 981#if ENABLE_FEATURE_COMMAND_EDITING_VI
963static int vi_mode;
964
965void setvimode(int viflag)
966{
967 vi_mode = viflag;
968}
969
970static void 982static void
971vi_Word_motion(char *command, int eat) 983vi_Word_motion(char *command, int eat)
972{ 984{
@@ -1058,13 +1070,11 @@ vi_back_motion(char *command)
1058 input_backward(1); 1070 input_backward(1);
1059 } 1071 }
1060} 1072}
1061#else
1062enum { vi_mode = 0 };
1063#endif 1073#endif
1064 1074
1065 1075
1066/* 1076/*
1067 * cmdedit_read_input and its helpers 1077 * read_line_input and its helpers
1068 */ 1078 */
1069 1079
1070#if !ENABLE_FEATURE_SH_FANCY_PROMPT 1080#if !ENABLE_FEATURE_SH_FANCY_PROMPT
@@ -1190,7 +1200,7 @@ static void parse_prompt(const char *prmt_ptr)
1190 cmdedit_prmt_len += cur_prmt_len; 1200 cmdedit_prmt_len += cur_prmt_len;
1191 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); 1201 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
1192 } 1202 }
1193 if (pwd_buf!=(char *)bb_msg_unknown) 1203 if (pwd_buf != (char *)bb_msg_unknown)
1194 free(pwd_buf); 1204 free(pwd_buf);
1195 cmdedit_prompt = prmt_mem_ptr; 1205 cmdedit_prompt = prmt_mem_ptr;
1196 put_prompt(); 1206 put_prompt();
@@ -1217,7 +1227,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg)
1217 /* new y for current cursor */ 1227 /* new y for current cursor */
1218 int new_y = (cursor + cmdedit_prmt_len) / w; 1228 int new_y = (cursor + cmdedit_prmt_len) / w;
1219 /* redraw */ 1229 /* redraw */
1220 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); 1230 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
1221 fflush(stdout); 1231 fflush(stdout);
1222 } 1232 }
1223} 1233}
@@ -1275,9 +1285,10 @@ static void cmdedit_init(void)
1275#undef CTRL 1285#undef CTRL
1276#define CTRL(a) ((a) & ~0x40) 1286#define CTRL(a) ((a) & ~0x40)
1277 1287
1278 1288int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *st)
1279int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1280{ 1289{
1290 static const int null_flags;
1291
1281 int lastWasTab = FALSE; 1292 int lastWasTab = FALSE;
1282 unsigned int ic; 1293 unsigned int ic;
1283 unsigned char c; 1294 unsigned char c;
@@ -1286,18 +1297,28 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1286 smallint vi_cmdmode = 0; 1297 smallint vi_cmdmode = 0;
1287 smalluint prevc; 1298 smalluint prevc;
1288#endif 1299#endif
1300
1301// FIXME: audit & improve this
1302 if (maxsize > BUFSIZ)
1303 maxsize = BUFSIZ;
1304
1305 /* With null flags, no other fields are ever used */
1306 state = st ? st : (line_input_t*) &null_flags;
1307 if (state->flags & SAVE_HISTORY)
1308 load_history(state->hist_file);
1309
1289 /* prepare before init handlers */ 1310 /* prepare before init handlers */
1290 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ 1311 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
1291 len = 0; 1312 command_len = 0;
1292 command_ps = command; 1313 command_ps = command;
1293 command[0] = '\0'; 1314 command[0] = '\0';
1294 1315
1295 getTermSettings(0, (void *) &initial_settings); 1316 getTermSettings(0, (void *) &initial_settings);
1296 memcpy(&new_settings, &initial_settings, sizeof(struct termios)); 1317 memcpy(&new_settings, &initial_settings, sizeof(new_settings));
1297 new_settings.c_lflag &= ~ICANON; /* unbuffered input */ 1318 new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1298 /* Turn off echoing and CTRL-C, so we can trap it */ 1319 /* Turn off echoing and CTRL-C, so we can trap it */
1299 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); 1320 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
1300 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ 1321 /* Hmm, in linux c_cc[] is not parsed if ICANON is off */
1301 new_settings.c_cc[VMIN] = 1; 1322 new_settings.c_cc[VMIN] = 1;
1302 new_settings.c_cc[VTIME] = 0; 1323 new_settings.c_cc[VTIME] = 0;
1303 /* Turn off CTRL-C, so we can trap it */ 1324 /* Turn off CTRL-C, so we can trap it */
@@ -1354,34 +1375,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1354 vi_case(CTRL('C')|vbit:) 1375 vi_case(CTRL('C')|vbit:)
1355 /* Control-c -- stop gathering input */ 1376 /* Control-c -- stop gathering input */
1356 goto_new_line(); 1377 goto_new_line();
1357#if !ENABLE_ASH 1378 command_len = 0;
1358 command[0] = '\0'; 1379 break_out = -1; /* "do not append '\n'" */
1359 len = 0;
1360 lastWasTab = FALSE;
1361 put_prompt();
1362#else
1363 len = 0;
1364 break_out = -1; /* to control traps */
1365#endif
1366 break; 1380 break;
1367 case CTRL('D'): 1381 case CTRL('D'):
1368 /* Control-d -- Delete one character, or exit 1382 /* Control-d -- Delete one character, or exit
1369 * if the len=0 and no chars to delete */ 1383 * if the len=0 and no chars to delete */
1370 if (len == 0) { 1384 if (command_len == 0) {
1371 errno = 0; 1385 errno = 0;
1372 prepare_to_die: 1386 prepare_to_die:
1373// So, our API depends on whether we have ash compiled in or not? Crap...
1374#if !ENABLE_ASH
1375 printf("exit");
1376 goto_new_line();
1377 /* cmdedit_reset_term() called in atexit */
1378// FIXME. this is definitely not good
1379 exit(EXIT_SUCCESS);
1380#else
1381 /* to control stopped jobs */ 1387 /* to control stopped jobs */
1382 break_out = len = -1; 1388 break_out = command_len = -1;
1383 break; 1389 break;
1384#endif
1385 } 1390 }
1386 input_delete(0); 1391 input_delete(0);
1387 break; 1392 break;
@@ -1407,23 +1412,21 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1407 break; 1412 break;
1408 1413
1409 case '\t': 1414 case '\t':
1410#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1411 input_tab(&lastWasTab); 1415 input_tab(&lastWasTab);
1412#endif
1413 break; 1416 break;
1414 1417
1415#if ENABLE_FEATURE_EDITING_FANCY_KEYS 1418#if ENABLE_FEATURE_EDITING_FANCY_KEYS
1416 case CTRL('K'): 1419 case CTRL('K'):
1417 /* Control-k -- clear to end of line */ 1420 /* Control-k -- clear to end of line */
1418 command[cursor] = 0; 1421 command[cursor] = 0;
1419 len = cursor; 1422 command_len = cursor;
1420 printf("\033[J"); 1423 printf("\033[J");
1421 break; 1424 break;
1422 case CTRL('L'): 1425 case CTRL('L'):
1423 vi_case(CTRL('L')|vbit:) 1426 vi_case(CTRL('L')|vbit:)
1424 /* Control-l -- clear screen */ 1427 /* Control-l -- clear screen */
1425 printf("\033[H"); 1428 printf("\033[H");
1426 redraw(0, len - cursor); 1429 redraw(0, command_len - cursor);
1427 break; 1430 break;
1428#endif 1431#endif
1429 1432
@@ -1439,12 +1442,11 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1439 vi_case(CTRL('P')|vbit:) 1442 vi_case(CTRL('P')|vbit:)
1440 vi_case('k'|vbit:) 1443 vi_case('k'|vbit:)
1441 /* Control-p -- Get previous command from history */ 1444 /* Control-p -- Get previous command from history */
1442 if (cur_history > 0) { 1445 if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
1443 get_previous_history(); 1446 get_previous_history();
1444 goto rewrite_line; 1447 goto rewrite_line;
1445 } else {
1446 beep();
1447 } 1448 }
1449 beep();
1448 break; 1450 break;
1449#endif 1451#endif
1450 1452
@@ -1454,7 +1456,8 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1454 /* Control-U -- Clear line before cursor */ 1456 /* Control-U -- Clear line before cursor */
1455 if (cursor) { 1457 if (cursor) {
1456 strcpy(command, command + cursor); 1458 strcpy(command, command + cursor);
1457 redraw(cmdedit_y, len -= cursor); 1459 command_len -= cursor;
1460 redraw(cmdedit_y, command_len);
1458 } 1461 }
1459 break; 1462 break;
1460#endif 1463#endif
@@ -1571,7 +1574,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1571 break; 1574 break;
1572 case '$': /* "d$", "c$" */ 1575 case '$': /* "d$", "c$" */
1573 clear_to_eol: 1576 clear_to_eol:
1574 while (cursor < len) 1577 while (cursor < command_len)
1575 input_delete(1); 1578 input_delete(1);
1576 break; 1579 break;
1577 } 1580 }
@@ -1599,7 +1602,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1599 case '\x1b': /* ESC */ 1602 case '\x1b': /* ESC */
1600 1603
1601#if ENABLE_FEATURE_COMMAND_EDITING_VI 1604#if ENABLE_FEATURE_COMMAND_EDITING_VI
1602 if (vi_mode) { 1605 if (state->flags & VI_MODE) {
1603 /* ESC: insert mode --> command mode */ 1606 /* ESC: insert mode --> command mode */
1604 vi_cmdmode = 1; 1607 vi_cmdmode = 1;
1605 input_backward(1); 1608 input_backward(1);
@@ -1634,7 +1637,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1634#if MAX_HISTORY > 0 1637#if MAX_HISTORY > 0
1635 case 'A': 1638 case 'A':
1636 /* Up Arrow -- Get previous command from history */ 1639 /* Up Arrow -- Get previous command from history */
1637 if (cur_history > 0) { 1640 if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
1638 get_previous_history(); 1641 get_previous_history();
1639 goto rewrite_line; 1642 goto rewrite_line;
1640 } 1643 }
@@ -1647,9 +1650,9 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1647 rewrite_line: 1650 rewrite_line:
1648 /* Rewrite the line with the selected history item */ 1651 /* Rewrite the line with the selected history item */
1649 /* change command */ 1652 /* change command */
1650 len = strlen(strcpy(command, history[cur_history])); 1653 command_len = strlen(strcpy(command, state->history[state->cur_history]));
1651 /* redraw and go to eol (bol, in vi */ 1654 /* redraw and go to eol (bol, in vi */
1652 redraw(cmdedit_y, vi_mode ? 9999 : 0); 1655 redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
1653 break; 1656 break;
1654#endif 1657#endif
1655 case 'C': 1658 case 'C':
@@ -1700,18 +1703,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1700 if (!Isprint(c)) /* Skip non-printable characters */ 1703 if (!Isprint(c)) /* Skip non-printable characters */
1701 break; 1704 break;
1702 1705
1703 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ 1706 if (command_len >= (maxsize - 2)) /* Need to leave space for enter */
1704 break; 1707 break;
1705 1708
1706 len++; 1709 command_len++;
1707 if (cursor == (len - 1)) { /* Append if at the end of the line */ 1710 if (cursor == (command_len - 1)) { /* Append if at the end of the line */
1708 command[cursor] = c; 1711 command[cursor] = c;
1709 command[cursor+1] = '\0'; 1712 command[cursor+1] = '\0';
1710 cmdedit_set_out_char(' '); 1713 cmdedit_set_out_char(' ');
1711 } else { /* Insert otherwise */ 1714 } else { /* Insert otherwise */
1712 int sc = cursor; 1715 int sc = cursor;
1713 1716
1714 memmove(command + sc + 1, command + sc, len - sc); 1717 memmove(command + sc + 1, command + sc, command_len - sc);
1715 command[sc] = c; 1718 command[sc] = c;
1716 sc++; 1719 sc++;
1717 /* rewrite from cursor */ 1720 /* rewrite from cursor */
@@ -1728,35 +1731,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1728 lastWasTab = FALSE; 1731 lastWasTab = FALSE;
1729 } 1732 }
1730 1733
1731#if MAX_HISTORY > 0 1734 if (command_len > 0)
1732 /* Handle command history log */ 1735 remember_in_history(command);
1733 /* cleanup may be saved current command line */
1734 if (len > 0) {
1735 int i = n_history;
1736
1737 free(history[MAX_HISTORY]);
1738 history[MAX_HISTORY] = NULL;
1739 /* After max history, remove the oldest command */
1740 if (i >= MAX_HISTORY) {
1741 free(history[0]);
1742 for (i = 0; i < MAX_HISTORY-1; i++)
1743 history[i] = history[i+1];
1744 }
1745// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
1746// (i.e. do not save dups?)
1747 history[i++] = xstrdup(command);
1748 cur_history = i;
1749 n_history = i;
1750 USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;)
1751 }
1752#else /* MAX_HISTORY == 0 */
1753 /* dont put empty line */
1754 USE_FEATURE_SH_FANCY_PROMPT(if (len > 0) num_ok_lines++;)
1755#endif /* MAX_HISTORY */
1756 1736
1757 if (break_out > 0) { 1737 if (break_out > 0) {
1758 command[len++] = '\n'; 1738 command[command_len++] = '\n';
1759 command[len] = '\0'; 1739 command[command_len] = '\0';
1760 } 1740 }
1761 1741
1762#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION 1742#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
@@ -1764,11 +1744,29 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1764#endif 1744#endif
1765 1745
1766#if ENABLE_FEATURE_SH_FANCY_PROMPT 1746#if ENABLE_FEATURE_SH_FANCY_PROMPT
1767 free(cmdedit_prompt); 1747 free((char*)cmdedit_prompt);
1768#endif 1748#endif
1769 /* restore initial_settings and SIGWINCH handler */ 1749 /* restore initial_settings and SIGWINCH handler */
1770 cmdedit_reset_term(); 1750 cmdedit_reset_term();
1771 return len; 1751 return command_len;
1752}
1753
1754line_input_t *new_line_input_t(int flags)
1755{
1756 line_input_t *n = xzalloc(sizeof(*n));
1757 n->flags = flags;
1758 return n;
1759}
1760
1761#else
1762
1763#undef read_line_input
1764int read_line_input(const char* prompt, char* command, int maxsize)
1765{
1766 fputs(prompt, stdout);
1767 fflush(stdout);
1768 fgets(command, maxsize, stdin);
1769 return strlen(command);
1772} 1770}
1773 1771
1774#endif /* FEATURE_COMMAND_EDITING */ 1772#endif /* FEATURE_COMMAND_EDITING */
@@ -1801,13 +1799,13 @@ int main(int argc, char **argv)
1801#endif 1799#endif
1802 while (1) { 1800 while (1) {
1803 int l; 1801 int l;
1804 l = cmdedit_read_input(prompt, buff); 1802 l = read_line_input(prompt, buff);
1805 if (l <= 0 || buff[l-1] != '\n') 1803 if (l <= 0 || buff[l-1] != '\n')
1806 break; 1804 break;
1807 buff[l-1] = 0; 1805 buff[l-1] = 0;
1808 printf("*** cmdedit_read_input() returned line =%s=\n", buff); 1806 printf("*** read_line_input() returned line =%s=\n", buff);
1809 } 1807 }
1810 printf("*** cmdedit_read_input() detect ^D\n"); 1808 printf("*** read_line_input() detect ^D\n");
1811 return 0; 1809 return 0;
1812} 1810}
1813 1811
diff --git a/shell/cmdedit.h b/shell/cmdedit.h
index 4a32cf63e..7af2f75fb 100644
--- a/shell/cmdedit.h
+++ b/shell/cmdedit.h
@@ -1,20 +1 @@
1/* vi: set sw=4 ts=4: */ /* TO DELETE */
2#ifndef CMDEDIT_H
3#define CMDEDIT_H
4
5int cmdedit_read_input(char* promptStr, char* command);
6
7#if ENABLE_ASH
8extern const char *cmdedit_path_lookup;
9#endif
10
11#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
12void load_history(const char *fromfile);
13void save_history(const char *tofile);
14#endif
15
16#if ENABLE_FEATURE_COMMAND_EDITING_VI
17void setvimode(int viflag);
18#endif
19
20#endif /* CMDEDIT_H */
diff --git a/shell/hush.c b/shell/hush.c
index 8f2dc80f2..2c88238ae 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -98,7 +98,6 @@
98/* #include <dmalloc.h> */ 98/* #include <dmalloc.h> */
99/* #define DEBUG_SHELL */ 99/* #define DEBUG_SHELL */
100 100
101#include "cmdedit.h"
102 101
103#define SPECIAL_VAR_SYMBOL 03 102#define SPECIAL_VAR_SYMBOL 03
104#define FLAG_EXIT_FROM_LOOP 1 103#define FLAG_EXIT_FROM_LOOP 1
@@ -883,20 +882,24 @@ static void setup_prompt_string(int promptmode, char **prompt_str)
883 debug_printf("result %s\n",*prompt_str); 882 debug_printf("result %s\n",*prompt_str);
884} 883}
885 884
885#if ENABLE_FEATURE_COMMAND_EDITING
886static line_input_t *line_input_state;
887#endif
888
886static void get_user_input(struct in_str *i) 889static void get_user_input(struct in_str *i)
887{ 890{
888 char *prompt_str; 891 char *prompt_str;
889 static char the_command[BUFSIZ]; 892 static char the_command[BUFSIZ];
890 893
891 setup_prompt_string(i->promptmode, &prompt_str); 894 setup_prompt_string(i->promptmode, &prompt_str);
892#ifdef CONFIG_FEATURE_COMMAND_EDITING 895#if ENABLE_FEATURE_COMMAND_EDITING
893 /* 896 /*
894 ** enable command line editing only while a command line 897 ** enable command line editing only while a command line
895 ** is actually being read; otherwise, we'll end up bequeathing 898 ** is actually being read; otherwise, we'll end up bequeathing
896 ** atexit() handlers and other unwanted stuff to our 899 ** atexit() handlers and other unwanted stuff to our
897 ** child processes (rob@sysgo.de) 900 ** child processes (rob@sysgo.de)
898 */ 901 */
899 cmdedit_read_input(prompt_str, the_command); 902 read_line_input(prompt_str, the_command, BUFSIZ, line_input_state);
900#else 903#else
901 fputs(prompt_str, stdout); 904 fputs(prompt_str, stdout);
902 fflush(stdout); 905 fflush(stdout);
@@ -2647,6 +2650,10 @@ int hush_main(int argc, char **argv)
2647 FILE *input; 2650 FILE *input;
2648 char **e = environ; 2651 char **e = environ;
2649 2652
2653#ifdef CONFIG_FEATURE_COMMAND_EDITING
2654 line_input_state = new_line_input_t(FOR_SHELL);
2655#endif
2656
2650 /* XXX what should these be while sourcing /etc/profile? */ 2657 /* XXX what should these be while sourcing /etc/profile? */
2651 global_argc = argc; 2658 global_argc = argc;
2652 global_argv = argv; 2659 global_argv = argv;
diff --git a/shell/lash.c b/shell/lash.c
index b2ccaf0a1..a09a9a9b1 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -23,8 +23,6 @@
23 23
24#include "busybox.h" 24#include "busybox.h"
25#include <getopt.h> 25#include <getopt.h>
26#include "cmdedit.h"
27
28#include <glob.h> 26#include <glob.h>
29#define expand_t glob_t 27#define expand_t glob_t
30 28
@@ -641,6 +639,10 @@ static inline void setup_prompt_string(char **prompt_str)
641#endif 639#endif
642} 640}
643 641
642#if ENABLE_FEATURE_COMMAND_EDITING
643static line_input_t *line_input_state;
644#endif
645
644static int get_command(FILE * source, char *command) 646static int get_command(FILE * source, char *command)
645{ 647{
646 char *prompt_str; 648 char *prompt_str;
@@ -659,14 +661,14 @@ static int get_command(FILE * source, char *command)
659 if (source == stdin) { 661 if (source == stdin) {
660 setup_prompt_string(&prompt_str); 662 setup_prompt_string(&prompt_str);
661 663
662#ifdef CONFIG_FEATURE_COMMAND_EDITING 664#if ENABLE_FEATURE_COMMAND_EDITING
663 /* 665 /*
664 ** enable command line editing only while a command line 666 ** enable command line editing only while a command line
665 ** is actually being read; otherwise, we'll end up bequeathing 667 ** is actually being read; otherwise, we'll end up bequeathing
666 ** atexit() handlers and other unwanted stuff to our 668 ** atexit() handlers and other unwanted stuff to our
667 ** child processes (rob@sysgo.de) 669 ** child processes (rob@sysgo.de)
668 */ 670 */
669 cmdedit_read_input(prompt_str, command); 671 read_line_input(prompt_str, command, BUFSIZ, line_input_state);
670 return 0; 672 return 0;
671#else 673#else
672 fputs(prompt_str, stdout); 674 fputs(prompt_str, stdout);
@@ -1505,6 +1507,10 @@ int lash_main(int argc_l, char **argv_l)
1505 argc = argc_l; 1507 argc = argc_l;
1506 argv = argv_l; 1508 argv = argv_l;
1507 1509
1510#if ENABLE_FEATURE_COMMAND_EDITING
1511 line_input_state = new_line_input_t(FOR_SHELL);
1512#endif
1513
1508 /* These variables need re-initializing when recursing */ 1514 /* These variables need re-initializing when recursing */
1509 last_jobid = 0; 1515 last_jobid = 0;
1510 close_me_list = NULL; 1516 close_me_list = NULL;
diff --git a/shell/msh.c b/shell/msh.c
index c88308f8f..8746e42bc 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -17,7 +17,6 @@
17#include <setjmp.h> 17#include <setjmp.h>
18#include <sys/times.h> 18#include <sys/times.h>
19 19
20#include "cmdedit.h"
21 20
22/*#define MSHDEBUG 1*/ 21/*#define MSHDEBUG 1*/
23 22
@@ -777,7 +776,7 @@ void print_tree(struct op *head)
777#endif /* MSHDEBUG */ 776#endif /* MSHDEBUG */
778 777
779 778
780#ifdef CONFIG_FEATURE_COMMAND_EDITING 779#if ENABLE_FEATURE_COMMAND_EDITING
781static char *current_prompt; 780static char *current_prompt;
782#endif 781#endif
783 782
@@ -787,6 +786,10 @@ static char *current_prompt;
787 */ 786 */
788 787
789 788
789#if ENABLE_FEATURE_COMMAND_EDITING
790static line_input_t *line_input_state;
791#endif
792
790int msh_main(int argc, char **argv) 793int msh_main(int argc, char **argv)
791{ 794{
792 int f; 795 int f;
@@ -795,6 +798,10 @@ int msh_main(int argc, char **argv)
795 char *name, **ap; 798 char *name, **ap;
796 int (*iof) (struct ioarg *); 799 int (*iof) (struct ioarg *);
797 800
801#if ENABLE_FEATURE_COMMAND_EDITING
802 line_input_state = new_line_input_t(FOR_SHELL);
803#endif
804
798 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); 805 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
799 806
800 initarea(); 807 initarea();
@@ -964,7 +971,7 @@ int msh_main(int argc, char **argv)
964 971
965 for (;;) { 972 for (;;) {
966 if (interactive && e.iop <= iostack) { 973 if (interactive && e.iop <= iostack) {
967#ifdef CONFIG_FEATURE_COMMAND_EDITING 974#if ENABLE_FEATURE_COMMAND_EDITING
968 current_prompt = prompt->value; 975 current_prompt = prompt->value;
969#else 976#else
970 prs(prompt->value); 977 prs(prompt->value);
@@ -2371,7 +2378,7 @@ static int yylex(int cf)
2371 startl = 1; 2378 startl = 1;
2372 if (multiline || cf & CONTIN) { 2379 if (multiline || cf & CONTIN) {
2373 if (interactive && e.iop <= iostack) { 2380 if (interactive && e.iop <= iostack) {
2374#ifdef CONFIG_FEATURE_COMMAND_EDITING 2381#if ENABLE_FEATURE_COMMAND_EDITING
2375 current_prompt = cprompt->value; 2382 current_prompt = cprompt->value;
2376#else 2383#else
2377 prs(cprompt->value); 2384 prs(cprompt->value);
@@ -2432,7 +2439,7 @@ static int collect(int c, int c1)
2432 return YYERRCODE; 2439 return YYERRCODE;
2433 } 2440 }
2434 if (interactive && c == '\n' && e.iop <= iostack) { 2441 if (interactive && c == '\n' && e.iop <= iostack) {
2435#ifdef CONFIG_FEATURE_COMMAND_EDITING 2442#if ENABLE_FEATURE_COMMAND_EDITING
2436 current_prompt = cprompt->value; 2443 current_prompt = cprompt->value;
2437#else 2444#else
2438 prs(cprompt->value); 2445 prs(cprompt->value);
@@ -4666,7 +4673,7 @@ static int readc(void)
4666 return e.iop->prev = 0; 4673 return e.iop->prev = 0;
4667 } 4674 }
4668 if (interactive && e.iop == iostack + 1) { 4675 if (interactive && e.iop == iostack + 1) {
4669#ifdef CONFIG_FEATURE_COMMAND_EDITING 4676#if ENABLE_FEATURE_COMMAND_EDITING
4670 current_prompt = prompt->value; 4677 current_prompt = prompt->value;
4671#else 4678#else
4672 prs(prompt->value); 4679 prs(prompt->value);
@@ -4898,13 +4905,13 @@ static int filechar(struct ioarg *ap)
4898 ap->afpos++; 4905 ap->afpos++;
4899 return *bp->bufp++ & 0177; 4906 return *bp->bufp++ & 0177;
4900 } 4907 }
4901#ifdef CONFIG_FEATURE_COMMAND_EDITING 4908#if ENABLE_FEATURE_COMMAND_EDITING
4902 if (interactive && isatty(ap->afile)) { 4909 if (interactive && isatty(ap->afile)) {
4903 static char mycommand[BUFSIZ]; 4910 static char mycommand[BUFSIZ];
4904 static int position = 0, size = 0; 4911 static int position = 0, size = 0;
4905 4912
4906 while (size == 0 || position >= size) { 4913 while (size == 0 || position >= size) {
4907 cmdedit_read_input(current_prompt, mycommand); 4914 read_line_input(current_prompt, mycommand, BUFSIZ, line_input_state);
4908 size = strlen(mycommand); 4915 size = strlen(mycommand);
4909 position = 0; 4916 position = 0;
4910 } 4917 }
@@ -4913,7 +4920,6 @@ static int filechar(struct ioarg *ap)
4913 return c; 4920 return c;
4914 } else 4921 } else
4915#endif 4922#endif
4916
4917 { 4923 {
4918 i = safe_read(ap->afile, &c, sizeof(c)); 4924 i = safe_read(ap->afile, &c, sizeof(c));
4919 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); 4925 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
@@ -5150,7 +5156,7 @@ static void readhere(char **name, char *s, int ec)
5150 e.iobase = e.iop; 5156 e.iobase = e.iop;
5151 for (;;) { 5157 for (;;) {
5152 if (interactive && e.iop <= iostack) { 5158 if (interactive && e.iop <= iostack) {
5153#ifdef CONFIG_FEATURE_COMMAND_EDITING 5159#if ENABLE_FEATURE_COMMAND_EDITING
5154 current_prompt = cprompt->value; 5160 current_prompt = cprompt->value;
5155#else 5161#else
5156 prs(cprompt->value); 5162 prs(cprompt->value);
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index cc6dfa57a..f15b9af91 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -202,7 +202,7 @@ static int get_boot(enum action what);
202 }) 202 })
203 203
204 204
205#define LINE_LENGTH 800 205#define LINE_LENGTH 80
206#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \ 206#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
207 (n) * sizeof(struct partition))) 207 (n) * sizeof(struct partition)))
208#define sector(s) ((s) & 0x3f) 208#define sector(s) ((s) & 0x3f)
@@ -291,16 +291,20 @@ write_part_table_flag(char *b)
291static char line_buffer[LINE_LENGTH]; 291static char line_buffer[LINE_LENGTH];
292static char *line_ptr; 292static char *line_ptr;
293 293
294/* read line; return 0 or first char */ 294/* read line; return 0 or first printable char */
295static int 295static int
296read_line(void) 296read_line(const char *prompt)
297{ 297{
298 fflush(stdout); /* requested by niles@scyld.com */ 298 int sz;
299
300 sz = read_line_input(prompt, line_buffer, LINE_LENGTH, NULL);
301 if (sz <= 0)
302 exit(0); /* Ctrl-D or Ctrl-C */
303
304 if (line_buffer[sz-1] == '\n')
305 line_buffer[--sz] = '\0';
306
299 line_ptr = line_buffer; 307 line_ptr = line_buffer;
300 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
301 /* error or eof */
302 bb_error_msg_and_die("\ngot EOF, exiting");
303 }
304 while (*line_ptr && !isgraph(*line_ptr)) 308 while (*line_ptr && !isgraph(*line_ptr))
305 line_ptr++; 309 line_ptr++;
306 return *line_ptr; 310 return *line_ptr;
@@ -309,22 +313,19 @@ read_line(void)
309static char 313static char
310read_nonempty(const char *mesg) 314read_nonempty(const char *mesg)
311{ 315{
312 do { 316 while (!read_line(mesg)) /* repeat */;
313 fputs(mesg, stdout);
314 } while (!read_line());
315 return *line_ptr; 317 return *line_ptr;
316} 318}
317 319
318static char 320static char
319read_maybe_empty(const char *mesg) 321read_maybe_empty(const char *mesg)
320{ 322{
321 fputs(mesg, stdout); 323 if (!read_line(mesg)) {
322 if (!read_line()) {
323 line_ptr = line_buffer; 324 line_ptr = line_buffer;
324 *line_ptr = '\n'; 325 line_ptr[0] = '\n';
325 line_ptr[1] = 0; 326 line_ptr[1] = '\0';
326 } 327 }
327 return *line_ptr; 328 return line_ptr[0];
328} 329}
329 330
330static int 331static int
@@ -469,9 +470,9 @@ static const struct systypes i386_sys_types[] = {
469 { "\x16" "Hidden FAT16" }, 470 { "\x16" "Hidden FAT16" },
470 { "\x17" "Hidden HPFS/NTFS" }, 471 { "\x17" "Hidden HPFS/NTFS" },
471 { "\x1b" "Hidden Win95 FAT32" }, 472 { "\x1b" "Hidden Win95 FAT32" },
472 { "\x1c" "Hidden Win95 FAT32 (LBA)" }, 473 { "\x1c" "Hidden W95 FAT32 (LBA)" },
473 { "\x1e" "Hidden Win95 FAT16 (LBA)" }, 474 { "\x1e" "Hidden W95 FAT16 (LBA)" },
474 { "\x3c" "PartitionMagic recovery" }, 475 { "\x3c" "Part.Magic recovery" },
475 { "\x41" "PPC PReP Boot" }, 476 { "\x41" "PPC PReP Boot" },
476 { "\x42" "SFS" }, 477 { "\x42" "SFS" },
477 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ 478 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
@@ -485,7 +486,7 @@ static const struct systypes i386_sys_types[] = {
485 { "\x87" "NTFS volume set" }, 486 { "\x87" "NTFS volume set" },
486 { "\x8e" "Linux LVM" }, 487 { "\x8e" "Linux LVM" },
487 { "\x9f" "BSD/OS" }, /* BSDI */ 488 { "\x9f" "BSD/OS" }, /* BSDI */
488 { "\xa0" "IBM Thinkpad hibernation" }, 489 { "\xa0" "Thinkpad hibernation" },
489 { "\xa5" "FreeBSD" }, /* various BSD flavours */ 490 { "\xa5" "FreeBSD" }, /* various BSD flavours */
490 { "\xa6" "OpenBSD" }, 491 { "\xa6" "OpenBSD" },
491 { "\xa8" "Darwin UFS" }, 492 { "\xa8" "Darwin UFS" },
@@ -718,71 +719,61 @@ is_dos_partition(int t)
718static void 719static void
719menu(void) 720menu(void)
720{ 721{
722 puts(_("Command Action"));
721 if (LABEL_IS_SUN) { 723 if (LABEL_IS_SUN) {
722 puts(_("Command action")); 724 puts(_("a\ttoggle a read only flag")); /* sun */
723 puts(_("\ta\ttoggle a read only flag")); /* sun */ 725 puts(_("b\tedit bsd disklabel"));
724 puts(_("\tb\tedit bsd disklabel")); 726 puts(_("c\ttoggle the mountable flag")); /* sun */
725 puts(_("\tc\ttoggle the mountable flag")); /* sun */ 727 puts(_("d\tdelete a partition"));
726 puts(_("\td\tdelete a partition")); 728 puts(_("l\tlist known partition types"));
727 puts(_("\tl\tlist known partition types")); 729 puts(_("n\tadd a new partition"));
728 puts(_("\tm\tprint this menu")); 730 puts(_("o\tcreate a new empty DOS partition table"));
729 puts(_("\tn\tadd a new partition")); 731 puts(_("p\tprint the partition table"));
730 puts(_("\to\tcreate a new empty DOS partition table")); 732 puts(_("q\tquit without saving changes"));
731 puts(_("\tp\tprint the partition table")); 733 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
732 puts(_("\tq\tquit without saving changes")); 734 puts(_("t\tchange a partition's system id"));
733 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */ 735 puts(_("u\tchange display/entry units"));
734 puts(_("\tt\tchange a partition's system id")); 736 puts(_("v\tverify the partition table"));
735 puts(_("\tu\tchange display/entry units")); 737 puts(_("w\twrite table to disk and exit"));
736 puts(_("\tv\tverify the partition table"));
737 puts(_("\tw\twrite table to disk and exit"));
738#if ENABLE_FEATURE_FDISK_ADVANCED 738#if ENABLE_FEATURE_FDISK_ADVANCED
739 puts(_("\tx\textra functionality (experts only)")); 739 puts(_("x\textra functionality (experts only)"));
740#endif 740#endif
741 } else 741 } else if (LABEL_IS_SGI) {
742 if (LABEL_IS_SGI) { 742 puts(_("a\tselect bootable partition")); /* sgi flavour */
743 puts(_("Command action")); 743 puts(_("b\tedit bootfile entry")); /* sgi */
744 puts(_("\ta\tselect bootable partition")); /* sgi flavour */ 744 puts(_("c\tselect sgi swap partition")); /* sgi flavour */
745 puts(_("\tb\tedit bootfile entry")); /* sgi */ 745 puts(_("d\tdelete a partition"));
746 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */ 746 puts(_("l\tlist known partition types"));
747 puts(_("\td\tdelete a partition")); 747 puts(_("n\tadd a new partition"));
748 puts(_("\tl\tlist known partition types")); 748 puts(_("o\tcreate a new empty DOS partition table"));
749 puts(_("\tm\tprint this menu")); 749 puts(_("p\tprint the partition table"));
750 puts(_("\tn\tadd a new partition")); 750 puts(_("q\tquit without saving changes"));
751 puts(_("\to\tcreate a new empty DOS partition table")); 751 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
752 puts(_("\tp\tprint the partition table")); 752 puts(_("t\tchange a partition's system id"));
753 puts(_("\tq\tquit without saving changes")); 753 puts(_("u\tchange display/entry units"));
754 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */ 754 puts(_("v\tverify the partition table"));
755 puts(_("\tt\tchange a partition's system id")); 755 puts(_("w\twrite table to disk and exit"));
756 puts(_("\tu\tchange display/entry units")); 756 } else if (LABEL_IS_AIX) {
757 puts(_("\tv\tverify the partition table")); 757 puts(_("o\tcreate a new empty DOS partition table"));
758 puts(_("\tw\twrite table to disk and exit")); 758 puts(_("q\tquit without saving changes"));
759 } else 759 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
760 if (LABEL_IS_AIX) { 760 } else {
761 puts(_("Command action")); 761 puts(_("a\ttoggle a bootable flag"));
762 puts(_("\tm\tprint this menu")); 762 puts(_("b\tedit bsd disklabel"));
763 puts(_("\to\tcreate a new empty DOS partition table")); 763 puts(_("c\ttoggle the dos compatibility flag"));
764 puts(_("\tq\tquit without saving changes")); 764 puts(_("d\tdelete a partition"));
765 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */ 765 puts(_("l\tlist known partition types"));
766 } else 766 puts(_("n\tadd a new partition"));
767 { 767 puts(_("o\tcreate a new empty DOS partition table"));
768 puts(_("Command action")); 768 puts(_("p\tprint the partition table"));
769 puts(_("\ta\ttoggle a bootable flag")); 769 puts(_("q\tquit without saving changes"));
770 puts(_("\tb\tedit bsd disklabel")); 770 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
771 puts(_("\tc\ttoggle the dos compatibility flag")); 771 puts(_("t\tchange a partition's system id"));
772 puts(_("\td\tdelete a partition")); 772 puts(_("u\tchange display/entry units"));
773 puts(_("\tl\tlist known partition types")); 773 puts(_("v\tverify the partition table"));
774 puts(_("\tm\tprint this menu")); 774 puts(_("w\twrite table to disk and exit"));
775 puts(_("\tn\tadd a new partition"));
776 puts(_("\to\tcreate a new empty DOS partition table"));
777 puts(_("\tp\tprint the partition table"));
778 puts(_("\tq\tquit without saving changes"));
779 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
780 puts(_("\tt\tchange a partition's system id"));
781 puts(_("\tu\tchange display/entry units"));
782 puts(_("\tv\tverify the partition table"));
783 puts(_("\tw\twrite table to disk and exit"));
784#if ENABLE_FEATURE_FDISK_ADVANCED 775#if ENABLE_FEATURE_FDISK_ADVANCED
785 puts(_("\tx\textra functionality (experts only)")); 776 puts(_("x\textra functionality (experts only)"));
786#endif 777#endif
787 } 778 }
788} 779}
@@ -793,73 +784,64 @@ menu(void)
793static void 784static void
794xmenu(void) 785xmenu(void)
795{ 786{
787 puts(_("Command Action"));
796 if (LABEL_IS_SUN) { 788 if (LABEL_IS_SUN) {
797 puts(_("Command action")); 789 puts(_("a\tchange number of alternate cylinders")); /*sun*/
798 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/ 790 puts(_("c\tchange number of cylinders"));
799 puts(_("\tc\tchange number of cylinders")); 791 puts(_("d\tprint the raw data in the partition table"));
800 puts(_("\td\tprint the raw data in the partition table")); 792 puts(_("e\tchange number of extra sectors per cylinder"));/*sun*/
801 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/ 793 puts(_("h\tchange number of heads"));
802 puts(_("\th\tchange number of heads")); 794 puts(_("i\tchange interleave factor")); /*sun*/
803 puts(_("\ti\tchange interleave factor")); /*sun*/ 795 puts(_("o\tchange rotation speed (rpm)")); /*sun*/
804 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/ 796 puts(_("p\tprint the partition table"));
805 puts(_("\tm\tprint this menu")); 797 puts(_("q\tquit without saving changes"));
806 puts(_("\tp\tprint the partition table")); 798 puts(_("r\treturn to main menu"));
807 puts(_("\tq\tquit without saving changes")); 799 puts(_("s\tchange number of sectors/track"));
808 puts(_("\tr\treturn to main menu")); 800 puts(_("v\tverify the partition table"));
809 puts(_("\ts\tchange number of sectors/track")); 801 puts(_("w\twrite table to disk and exit"));
810 puts(_("\tv\tverify the partition table")); 802 puts(_("y\tchange number of physical cylinders")); /*sun*/
811 puts(_("\tw\twrite table to disk and exit")); 803 } else if (LABEL_IS_SGI) {
812 puts(_("\ty\tchange number of physical cylinders")); /*sun*/ 804 puts(_("b\tmove beginning of data in a partition")); /* !sun */
813 } else 805 puts(_("c\tchange number of cylinders"));
814 if (LABEL_IS_SGI) { 806 puts(_("d\tprint the raw data in the partition table"));
815 puts(_("Command action")); 807 puts(_("e\tlist extended partitions")); /* !sun */
816 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */ 808 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
817 puts(_("\tc\tchange number of cylinders")); 809 puts(_("h\tchange number of heads"));
818 puts(_("\td\tprint the raw data in the partition table")); 810 puts(_("p\tprint the partition table"));
819 puts(_("\te\tlist extended partitions")); /* !sun */ 811 puts(_("q\tquit without saving changes"));
820 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */ 812 puts(_("r\treturn to main menu"));
821 puts(_("\th\tchange number of heads")); 813 puts(_("s\tchange number of sectors/track"));
822 puts(_("\tm\tprint this menu")); 814 puts(_("v\tverify the partition table"));
823 puts(_("\tp\tprint the partition table")); 815 puts(_("w\twrite table to disk and exit"));
824 puts(_("\tq\tquit without saving changes")); 816 } else if (LABEL_IS_AIX) {
825 puts(_("\tr\treturn to main menu")); 817 puts(_("b\tmove beginning of data in a partition")); /* !sun */
826 puts(_("\ts\tchange number of sectors/track")); 818 puts(_("c\tchange number of cylinders"));
827 puts(_("\tv\tverify the partition table")); 819 puts(_("d\tprint the raw data in the partition table"));
828 puts(_("\tw\twrite table to disk and exit")); 820 puts(_("e\tlist extended partitions")); /* !sun */
829 } else 821 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
830 if (LABEL_IS_AIX) { 822 puts(_("h\tchange number of heads"));
831 puts(_("Command action")); 823 puts(_("p\tprint the partition table"));
832 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */ 824 puts(_("q\tquit without saving changes"));
833 puts(_("\tc\tchange number of cylinders")); 825 puts(_("r\treturn to main menu"));
834 puts(_("\td\tprint the raw data in the partition table")); 826 puts(_("s\tchange number of sectors/track"));
835 puts(_("\te\tlist extended partitions")); /* !sun */ 827 puts(_("v\tverify the partition table"));
836 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */ 828 puts(_("w\twrite table to disk and exit"));
837 puts(_("\th\tchange number of heads")); 829 } else {
838 puts(_("\tm\tprint this menu")); 830 puts(_("b\tmove beginning of data in a partition")); /* !sun */
839 puts(_("\tp\tprint the partition table")); 831 puts(_("c\tchange number of cylinders"));
840 puts(_("\tq\tquit without saving changes")); 832 puts(_("d\tprint the raw data in the partition table"));
841 puts(_("\tr\treturn to main menu")); 833 puts(_("e\tlist extended partitions")); /* !sun */
842 puts(_("\ts\tchange number of sectors/track")); 834 puts(_("f\tfix partition order")); /* !sun, !aix, !sgi */
843 puts(_("\tv\tverify the partition table"));
844 puts(_("\tw\twrite table to disk and exit"));
845 } else {
846 puts(_("Command action"));
847 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
848 puts(_("\tc\tchange number of cylinders"));
849 puts(_("\td\tprint the raw data in the partition table"));
850 puts(_("\te\tlist extended partitions")); /* !sun */
851 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
852#if ENABLE_FEATURE_SGI_LABEL 835#if ENABLE_FEATURE_SGI_LABEL
853 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */ 836 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
854#endif 837#endif
855 puts(_("\th\tchange number of heads")); 838 puts(_("h\tchange number of heads"));
856 puts(_("\tm\tprint this menu")); 839 puts(_("p\tprint the partition table"));
857 puts(_("\tp\tprint the partition table")); 840 puts(_("q\tquit without saving changes"));
858 puts(_("\tq\tquit without saving changes")); 841 puts(_("r\treturn to main menu"));
859 puts(_("\tr\treturn to main menu")); 842 puts(_("s\tchange number of sectors/track"));
860 puts(_("\ts\tchange number of sectors/track")); 843 puts(_("v\tverify the partition table"));
861 puts(_("\tv\tverify the partition table")); 844 puts(_("w\twrite table to disk and exit"));
862 puts(_("\tw\twrite table to disk and exit"));
863 } 845 }
864} 846}
865#endif /* ADVANCED mode */ 847#endif /* ADVANCED mode */
@@ -883,7 +865,7 @@ static const char *partition_type(unsigned char type)
883 const struct systypes *types = get_sys_types(); 865 const struct systypes *types = get_sys_types();
884 866
885 for (i = 0; types[i].name; i++) 867 for (i = 0; types[i].name; i++)
886 if ((unsigned char )types[i].name[0] == type) 868 if ((unsigned char)types[i].name[0] == type)
887 return types[i].name + 1; 869 return types[i].name + 1;
888 870
889 return _("Unknown"); 871 return _("Unknown");
@@ -899,24 +881,29 @@ get_sysid(int i)
899 ptes[i].part_table->sys_ind); 881 ptes[i].part_table->sys_ind);
900} 882}
901 883
902void list_types(const struct systypes *sys) 884static void list_types(const struct systypes *sys)
903{ 885{
904 unsigned last[4], done = 0, next = 0, size; 886 enum { COLS = 3 };
887
888 unsigned last[COLS];
889 unsigned done, next, size;
905 int i; 890 int i;
906 891
907 for (i = 0; sys[i].name; i++); 892 for (size = 0; sys[size].name; size++) /* */;
908 size = i;
909 893
910 for (i = 3; i >= 0; i--) 894 done = 0;
911 last[3 - i] = done += (size + i - done) / (i + 1); 895 for (i = COLS-1; i >= 0; i--) {
912 i = done = 0; 896 done += (size + i - done) / (i + 1);
897 last[COLS-1 - i] = done;
898 }
913 899
900 i = done = next = 0;
914 do { 901 do {
915 printf("%c%2x %-15.15s", i ? ' ' : '\n', 902 printf("%c%2x %-22.22s", i ? ' ' : '\n',
916 (unsigned char)sys[next].name[0], 903 (unsigned char)sys[next].name[0],
917 partition_type((unsigned char)sys[next].name[0])); 904 sys[next].name + 1);
918 next = last[i++] + done; 905 next = last[i++] + done;
919 if (i > 3 || next >= last[i]) { 906 if (i >= COLS || next >= last[i]) {
920 i = 0; 907 i = 0;
921 next = ++done; 908 next = ++done;
922 } 909 }
@@ -2415,10 +2402,12 @@ new_partition(void)
2415 "an extended partition first\n")); 2402 "an extended partition first\n"));
2416 } else { 2403 } else {
2417 char c, line[LINE_LENGTH]; 2404 char c, line[LINE_LENGTH];
2418 snprintf(line, sizeof(line), "%s\n %s\n p primary " 2405 snprintf(line, sizeof(line),
2419 "partition (1-4)\n", 2406 "Command action\n"
2420 "Command action", (extended_offset ? 2407 " %s\n"
2421 "l logical (5 or over)" : "e extended")); 2408 " p primary partition (1-4)\n",
2409 (extended_offset ?
2410 "l logical (5 or over)" : "e extended"));
2422 while (1) { 2411 while (1) {
2423 c = read_nonempty(line); 2412 c = read_nonempty(line);
2424 if (c == 'p' || c == 'P') { 2413 if (c == 'p' || c == 'P') {
diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c
index 16a046ea3..3f56bd27d 100644
--- a/util-linux/fdisk_osf.c
+++ b/util-linux/fdisk_osf.c
@@ -308,22 +308,21 @@ bsd_trydev(const char * dev)
308static void 308static void
309bsd_menu(void) 309bsd_menu(void)
310{ 310{
311 puts(_("Command action")); 311 puts(_("Command Action"));
312 puts(_("\td\tdelete a BSD partition")); 312 puts(_("d\tdelete a BSD partition"));
313 puts(_("\te\tedit drive data")); 313 puts(_("e\tedit drive data"));
314 puts(_("\ti\tinstall bootstrap")); 314 puts(_("i\tinstall bootstrap"));
315 puts(_("\tl\tlist known filesystem types")); 315 puts(_("l\tlist known filesystem types"));
316 puts(_("\tm\tprint this menu")); 316 puts(_("n\tadd a new BSD partition"));
317 puts(_("\tn\tadd a new BSD partition")); 317 puts(_("p\tprint BSD partition table"));
318 puts(_("\tp\tprint BSD partition table")); 318 puts(_("q\tquit without saving changes"));
319 puts(_("\tq\tquit without saving changes")); 319 puts(_("r\treturn to main menu"));
320 puts(_("\tr\treturn to main menu")); 320 puts(_("s\tshow complete disklabel"));
321 puts(_("\ts\tshow complete disklabel")); 321 puts(_("t\tchange a partition's filesystem id"));
322 puts(_("\tt\tchange a partition's filesystem id")); 322 puts(_("u\tchange units (cylinders/sectors)"));
323 puts(_("\tu\tchange units (cylinders/sectors)")); 323 puts(_("w\twrite disklabel to disk"));
324 puts(_("\tw\twrite disklabel to disk"));
325#if !defined(__alpha__) 324#if !defined(__alpha__)
326 puts(_("\tx\tlink BSD partition to non-BSD partition")); 325 puts(_("x\tlink BSD partition to non-BSD partition"));
327#endif 326#endif
328} 327}
329 328
@@ -633,13 +632,15 @@ xbsd_create_disklabel(void)
633static int 632static int
634edit_int(int def, char *mesg) 633edit_int(int def, char *mesg)
635{ 634{
635 mesg = xasprintf("%s (%d): ", mesg, def);
636 do { 636 do {
637 fputs(mesg, stdout); 637 if (!read_line(mesg))
638 printf(" (%d): ", def); 638 goto ret;
639 if (!read_line())
640 return def;
641 } while (!isdigit(*line_ptr)); 639 } while (!isdigit(*line_ptr));
642 return atoi(line_ptr); 640 def = atoi(line_ptr);
641 ret:
642 free(mesg);
643 return def;
643} 644}
644 645
645static void 646static void
@@ -718,10 +719,9 @@ xbsd_write_bootstrap(void)
718 else 719 else
719 dkbasename = "wd"; 720 dkbasename = "wd";
720 721
721 printf(_("Bootstrap: %sboot -> boot%s (%s): "), 722 snprintf(path, sizeof(path), "Bootstrap: %sboot -> boot%s (%s): ",
722 dkbasename, dkbasename, dkbasename); 723 dkbasename, dkbasename, dkbasename);
723 if (read_line()) { 724 if (read_line(path)) {
724 line_ptr[strlen(line_ptr)-1] = '\0';
725 dkbasename = line_ptr; 725 dkbasename = line_ptr;
726 } 726 }
727 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename); 727 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);