readline: Allow only ascii and printable characters
[barebox-mini2440.git] / lib / readline.c
blob750da3b59c03afe919992ac495e31350aaeedfcd
1 #include <common.h>
2 #include <readkey.h>
3 #include <init.h>
4 #include <xfuncs.h>
5 #include <complete.h>
6 #include <linux/ctype.h>
8 /*
9 * cmdline-editing related codes from vivi.
10 * Author: Janghoon Lyu <nandy@mizi.com>
13 #define putnstr(str,n) do { \
14 printf ("%.*s", n, str); \
15 } while (0)
17 #define MAX_CMDBUF_SIZE 256
19 #define CTL_BACKSPACE ('\b')
20 #define DEL ((char)255)
21 #define DEL7 ((char)127)
22 #define CREAD_HIST_CHAR ('!')
24 #define getcmd_putch(ch) putchar(ch)
25 #define getcmd_getch() getc()
26 #define getcmd_cbeep() getcmd_putch('\a')
28 #define HIST_MAX 20
29 #define HIST_SIZE MAX_CMDBUF_SIZE
31 static int hist_max = 0;
32 static int hist_add_idx = 0;
33 static int hist_cur = -1;
34 static unsigned hist_num = 0;
36 static char* hist_list[HIST_MAX];
37 static char hist_lines[HIST_MAX][HIST_SIZE];
39 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
41 static int hist_init(void)
43 int i;
45 hist_max = 0;
46 hist_add_idx = 0;
47 hist_cur = -1;
48 hist_num = 0;
50 for (i = 0; i < HIST_MAX; i++) {
51 hist_list[i] = hist_lines[i];
52 hist_list[i][0] = '\0';
54 return 0;
57 postcore_initcall(hist_init);
59 static void cread_add_to_hist(char *line)
61 strcpy(hist_list[hist_add_idx], line);
63 if (++hist_add_idx >= HIST_MAX)
64 hist_add_idx = 0;
66 if (hist_add_idx > hist_max)
67 hist_max = hist_add_idx;
69 hist_num++;
72 static char* hist_prev(void)
74 char *ret;
75 int old_cur;
77 if (hist_cur < 0)
78 return NULL;
80 old_cur = hist_cur;
81 if (--hist_cur < 0)
82 hist_cur = hist_max;
84 if (hist_cur == hist_add_idx) {
85 hist_cur = old_cur;
86 ret = NULL;
87 } else
88 ret = hist_list[hist_cur];
90 return (ret);
93 static char* hist_next(void)
95 char *ret;
97 if (hist_cur < 0)
98 return NULL;
100 if (hist_cur == hist_add_idx)
101 return NULL;
103 if (++hist_cur > hist_max)
104 hist_cur = 0;
106 if (hist_cur == hist_add_idx) {
107 ret = "";
108 } else
109 ret = hist_list[hist_cur];
111 return (ret);
114 #define BEGINNING_OF_LINE() { \
115 while (num) { \
116 getcmd_putch(CTL_BACKSPACE); \
117 num--; \
121 #define ERASE_TO_EOL() { \
122 if (num < eol_num) { \
123 int tmp; \
124 for (tmp = num; tmp < eol_num; tmp++) \
125 getcmd_putch(' '); \
126 while (tmp-- > num) \
127 getcmd_putch(CTL_BACKSPACE); \
128 eol_num = num; \
132 #define REFRESH_TO_EOL() { \
133 if (num < eol_num) { \
134 wlen = eol_num - num; \
135 putnstr(buf + num, wlen); \
136 num = eol_num; \
140 static void cread_add_char(char ichar, int insert, unsigned long *num,
141 unsigned long *eol_num, char *buf, unsigned long len)
143 unsigned long wlen;
145 /* room ??? */
146 if (insert || *num == *eol_num) {
147 if (*eol_num > len - 1) {
148 getcmd_cbeep();
149 return;
151 (*eol_num)++;
154 if (insert) {
155 wlen = *eol_num - *num;
156 if (wlen > 1) {
157 memmove(&buf[*num+1], &buf[*num], wlen-1);
160 buf[*num] = ichar;
161 putnstr(buf + *num, wlen);
162 (*num)++;
163 while (--wlen) {
164 getcmd_putch(CTL_BACKSPACE);
166 } else {
167 /* echo the character */
168 wlen = 1;
169 buf[*num] = ichar;
170 putnstr(buf + *num, wlen);
171 (*num)++;
175 int readline(const char *prompt, char *buf, int len)
177 unsigned long num = 0;
178 unsigned long eol_num = 0;
179 unsigned long rlen;
180 unsigned long wlen;
181 unsigned char ichar;
182 int insert = 1;
183 int rc = 0;
184 #ifdef CONFIG_AUTO_COMPLETE
185 char tmp;
186 int reprint, i;
187 char *completestr;
189 complete_reset();
190 #endif
191 puts (prompt);
193 while (1) {
194 rlen = 1;
195 ichar = read_key();
197 if ((ichar == '\n') || (ichar == '\r')) {
198 putchar('\n');
199 break;
202 switch (ichar) {
203 case '\t':
204 #ifdef CONFIG_AUTO_COMPLETE
205 buf[eol_num] = 0;
206 tmp = buf[num];
208 buf[num] = 0;
209 reprint = complete(buf, &completestr);
210 buf[num] = tmp;
212 if (reprint) {
213 printf("%s%s", prompt, buf);
215 if (tmp)
216 for (i = 0; i < eol_num - num; i++)
217 getcmd_putch(CTL_BACKSPACE);
220 i = 0;
221 while (completestr[i])
222 cread_add_char(completestr[i++], insert, &num,
223 &eol_num, buf, len);
224 #endif
225 break;
227 case KEY_HOME:
228 BEGINNING_OF_LINE();
229 break;
230 case CTL_CH('c'): /* ^C - break */
231 *buf = 0; /* discard input */
232 return -1;
233 case KEY_RIGHT:
234 if (num < eol_num) {
235 getcmd_putch(buf[num]);
236 num++;
238 break;
239 case KEY_LEFT:
240 if (num) {
241 getcmd_putch(CTL_BACKSPACE);
242 num--;
244 break;
245 case CTL_CH('d'):
246 if (num < eol_num) {
247 wlen = eol_num - num - 1;
248 if (wlen) {
249 memmove(&buf[num], &buf[num+1], wlen);
250 putnstr(buf + num, wlen);
253 getcmd_putch(' ');
254 do {
255 getcmd_putch(CTL_BACKSPACE);
256 } while (wlen--);
257 eol_num--;
259 break;
260 case KEY_ERASE_TO_EOL:
261 ERASE_TO_EOL();
262 break;
263 case KEY_REFRESH_TO_EOL:
264 case KEY_END:
265 REFRESH_TO_EOL();
266 break;
267 case KEY_INSERT:
268 insert = !insert;
269 break;
270 case KEY_ERASE_LINE:
271 BEGINNING_OF_LINE();
272 ERASE_TO_EOL();
273 break;
274 case DEL:
275 case KEY_DEL7:
276 case 8:
277 if (num) {
278 wlen = eol_num - num;
279 num--;
280 memmove(buf + num, buf + num + 1, wlen);
281 getcmd_putch(CTL_BACKSPACE);
282 putnstr(buf + num, wlen);
283 getcmd_putch(' ');
284 do {
285 getcmd_putch(CTL_BACKSPACE);
286 } while (wlen--);
287 eol_num--;
289 break;
290 case KEY_DEL:
291 if (num < eol_num) {
292 wlen = eol_num - num;
293 memmove(buf + num, buf + num + 1, wlen);
294 putnstr(buf + num, wlen - 1);
295 getcmd_putch(' ');
296 do {
297 getcmd_putch(CTL_BACKSPACE);
298 } while (--wlen);
299 eol_num--;
301 break;
302 case KEY_UP:
303 case KEY_DOWN:
305 char * hline;
307 if (ichar == KEY_UP)
308 hline = hist_prev();
309 else
310 hline = hist_next();
312 if (!hline) {
313 getcmd_cbeep();
314 continue;
317 /* nuke the current line */
318 /* first, go home */
319 BEGINNING_OF_LINE();
321 /* erase to end of line */
322 ERASE_TO_EOL();
324 /* copy new line into place and display */
325 strcpy(buf, hline);
326 eol_num = strlen(buf);
327 REFRESH_TO_EOL();
328 continue;
330 default:
331 if (isascii(ichar) && isprint(ichar))
332 cread_add_char(ichar, insert, &num, &eol_num, buf, len);
333 break;
336 len = eol_num;
337 buf[eol_num] = '\0'; /* lose the newline */
339 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
340 cread_add_to_hist(buf);
341 hist_cur = hist_add_idx;
343 return rc < 0 ? rc : len;