ldlinux: Fix serial output and delete eprintf()
[syslinux.git] / com32 / elflink / ldlinux / cli.c
blobb85357b2020e39467a5a75d6094e9bbafdfab6e5
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <console.h>
5 #include <com32.h>
6 #include <syslinux/adv.h>
7 #include <syslinux/config.h>
8 #include <setjmp.h>
9 #include <netinet/in.h>
10 #include <limits.h>
11 #include <minmax.h>
12 #include <linux/list.h>
13 #include <sys/exec.h>
14 #include <sys/module.h>
15 #include <dprintf.h>
16 #include <core.h>
18 #include "getkey.h"
19 #include "menu.h"
20 #include "cli.h"
21 #include "config.h"
23 static struct list_head cli_history_head;
25 void clear_screen(void)
27 //dprintf("enter");
28 fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
31 static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto)
33 clock_t t0, t1;
34 int key;
36 t0 = times(NULL);
37 key = get_key(stdin, *kbd_to ? *kbd_to : *tto);
39 /* kbdtimeout only applies to the first character */
40 if (*kbd_to)
41 *kbd_to = 0;
43 t1 = times(NULL) - t0;
44 if (*tto) {
45 /* Timed out. */
46 if (*tto <= (long long)t1)
47 key = KEY_NONE;
48 else {
49 /* Did it wrap? */
50 if (*tto > totaltimeout)
51 key = KEY_NONE;
53 *tto -= t1;
57 return key;
60 static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
61 clock_t *tto)
63 int key;
64 int i = 0;
65 char buf[MAX_CMDLINE_LEN];
66 const char *p = NULL;
67 struct cli_command *last_found;
68 struct cli_command *last_good = NULL;
70 last_found = list_entry(cli_history_head.next, typeof(*last_found), list);
72 memset(buf, 0, MAX_CMDLINE_LEN);
74 printf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m");
75 while (1) {
76 key = mygetkey_timeout(kbd_to, tto);
78 if (key == KEY_CTRL('C')) {
79 return NULL;
80 } else if (key == KEY_CTRL('R')) {
81 if (i == 0)
82 continue; /* User typed nothing yet */
83 /* User typed 'CTRL-R' again, so try the next */
84 last_found = list_entry(last_found->list.next, typeof(*last_found), list);
85 } else if (key >= ' ' && key <= 'z') {
86 buf[i++] = key;
87 } else {
88 /* Treat other input chars as terminal */
89 break;
92 while (!list_is_last(&last_found->list, &cli_history_head)) {
93 p = strstr(last_found->command, buf);
94 if (p)
95 break;
96 last_found = list_entry(last_found->list.next, typeof(*last_found), list);
99 if (!p && !last_good) {
100 return NULL;
101 } else if (!p) {
102 continue;
103 } else {
104 last_good = last_found;
105 *cursor = p - last_good->command;
108 printf("\033[?7l\033[?25l");
109 /* Didn't handle the line wrap case here */
110 printf("\033[1G\033[1;36m(reverse-i-search)\033[0m`%s': %s",
111 buf, last_good->command ? : "");
112 printf("\033[K\r");
115 return last_good ? last_good->command : NULL;
120 const char *edit_cmdline(const char *input, int top /*, int width */ ,
121 int (*pDraw_Menu) (int, int, int),
122 void (*show_fkey) (int), bool *timedout)
124 char cmdline[MAX_CMDLINE_LEN] = { };
125 int key, len, prev_len, cursor;
126 int redraw = 0;
127 int x, y;
128 bool done = false;
129 const char *ret;
130 int width = 0;
131 struct cli_command *comm_counter = NULL;
132 clock_t kbd_to = kbdtimeout;
133 clock_t tto = totaltimeout;
135 if (!width) {
136 int height;
137 if (getscreensize(1, &height, &width))
138 width = 80;
141 len = cursor = 0;
142 prev_len = 0;
143 x = y = 0;
146 * Before we start messing with the x,y coordinates print 'input'
147 * so that it follows whatever text has been written to the screen
148 * previously.
150 printf("%s ", input);
152 while (!done) {
153 if (redraw > 1) {
154 /* Clear and redraw whole screen */
155 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
156 to avoid confusing the Linux console */
157 clear_screen();
158 if (pDraw_Menu)
159 (*pDraw_Menu) (-1, top, 1);
160 prev_len = 0;
161 printf("\033[2J\033[H");
162 // printf("\033[0m\033[2J\033[H");
165 if (redraw > 0) {
166 int dy, at;
168 prev_len = max(len, prev_len);
170 /* Redraw the command line */
171 printf("\033[?7l\033[?25l");
172 printf("\033[1G%s ", input);
174 x = strlen(input);
175 y = 0;
176 at = 0;
177 while (at < prev_len) {
178 putchar(at >= len ? ' ' : cmdline[at]);
179 at++;
180 x++;
181 if (x >= width) {
182 printf("\r\n");
183 x = 0;
184 y++;
187 printf("\033[K\r");
189 dy = y - (cursor + strlen(input) + 1) / width;
190 x = (cursor + strlen(input) + 1) % width;
192 if (dy) {
193 printf("\033[%dA", dy);
194 y -= dy;
196 if (x)
197 printf("\033[%dC", x);
198 printf("\033[?25h");
199 prev_len = len;
200 redraw = 0;
203 key = mygetkey_timeout(&kbd_to, &tto);
205 switch (key) {
206 case KEY_NONE:
207 /* We timed out. */
208 *timedout = true;
209 return NULL;
211 case KEY_CTRL('L'):
212 redraw = 2;
213 break;
215 case KEY_ENTER:
216 case KEY_CTRL('J'):
217 ret = cmdline;
218 done = true;
219 break;
221 case KEY_BACKSPACE:
222 case KEY_DEL:
223 if (cursor) {
224 memmove(cmdline + cursor - 1, cmdline + cursor,
225 len - cursor + 1);
226 len--;
227 cursor--;
228 redraw = 1;
230 break;
232 case KEY_CTRL('D'):
233 case KEY_DELETE:
234 if (cursor < len) {
235 memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
236 len--;
237 redraw = 1;
239 break;
241 case KEY_CTRL('U'):
242 if (len) {
243 len = cursor = 0;
244 cmdline[len] = '\0';
245 redraw = 1;
247 break;
249 case KEY_CTRL('W'):
250 if (cursor) {
251 int prevcursor = cursor;
253 while (cursor && my_isspace(cmdline[cursor - 1]))
254 cursor--;
256 while (cursor && !my_isspace(cmdline[cursor - 1]))
257 cursor--;
259 #if 0
260 memmove(cmdline + cursor, cmdline + prevcursor,
261 len - prevcursor + 1);
262 #else
264 int i;
265 char *q = cmdline + cursor;
266 char *p = cmdline + prevcursor;
267 for (i = 0; i < len - prevcursor + 1; i++)
268 *q++ = *p++;
270 #endif
271 len -= (prevcursor - cursor);
272 redraw = 1;
274 break;
276 case KEY_LEFT:
277 case KEY_CTRL('B'):
278 if (cursor) {
279 cursor--;
280 redraw = 1;
282 break;
284 case KEY_RIGHT:
285 case KEY_CTRL('F'):
286 if (cursor < len) {
287 putchar(cmdline[cursor]);
288 cursor++;
289 x++;
290 if (x >= width) {
291 printf("\r\n");
292 y++;
293 x = 0;
296 break;
298 case KEY_CTRL('K'):
299 if (cursor < len) {
300 cmdline[len = cursor] = '\0';
301 redraw = 1;
303 break;
305 case KEY_HOME:
306 case KEY_CTRL('A'):
307 if (cursor) {
308 cursor = 0;
309 redraw = 1;
311 break;
313 case KEY_END:
314 case KEY_CTRL('E'):
315 if (cursor != len) {
316 cursor = len;
317 redraw = 1;
319 break;
321 case KEY_F1:
322 case KEY_F2:
323 case KEY_F3:
324 case KEY_F4:
325 case KEY_F5:
326 case KEY_F6:
327 case KEY_F7:
328 case KEY_F8:
329 case KEY_F9:
330 case KEY_F10:
331 case KEY_F11:
332 case KEY_F12:
333 if (show_fkey != NULL) {
334 (*show_fkey) (key);
335 redraw = 1;
337 break;
338 case KEY_CTRL('P'):
339 case KEY_UP:
341 if (!list_empty(&cli_history_head)) {
342 struct list_head *next;
344 if (!comm_counter)
345 next = cli_history_head.next;
346 else
347 next = comm_counter->list.next;
349 comm_counter =
350 list_entry(next, typeof(*comm_counter), list);
352 if (&comm_counter->list != &cli_history_head)
353 strcpy(cmdline, comm_counter->command);
355 cursor = len = strlen(cmdline);
356 redraw = 1;
359 break;
360 case KEY_CTRL('N'):
361 case KEY_DOWN:
363 if (!list_empty(&cli_history_head)) {
364 struct list_head *prev;
366 if (!comm_counter)
367 prev = cli_history_head.prev;
368 else
369 prev = comm_counter->list.prev;
371 comm_counter =
372 list_entry(prev, typeof(*comm_counter), list);
374 if (&comm_counter->list != &cli_history_head)
375 strcpy(cmdline, comm_counter->command);
377 cursor = len = strlen(cmdline);
378 redraw = 1;
381 break;
382 case KEY_CTRL('R'):
385 * Handle this case in another function, since it's
386 * a kind of special.
388 const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto);
389 if (p) {
390 strcpy(cmdline, p);
391 len = strlen(cmdline);
392 } else {
393 cmdline[0] = '\0';
394 len = 0;
396 redraw = 1;
398 break;
399 case KEY_TAB:
401 const char *p;
402 size_t len;
404 /* Label completion enabled? */
405 if (nocomplete)
406 break;
408 p = cmdline;
409 len = 0;
410 while(*p && !my_isspace(*p)) {
411 p++;
412 len++;
415 print_labels(cmdline, len);
416 redraw = 1;
417 break;
419 case KEY_CTRL('V'):
420 if (BIOSName)
421 printf("%s%s%s", syslinux_banner,
422 (char *)MK_PTR(0, BIOSName), copyright_str);
423 else
424 printf("%s%s", syslinux_banner, copyright_str);
426 redraw = 1;
427 break;
429 default:
430 if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
431 if (cursor == len) {
432 cmdline[len++] = key;
433 cmdline[len] = '\0';
434 putchar(key);
435 cursor++;
436 x++;
437 if (x >= width) {
438 printf("\r\n\033[K");
439 y++;
440 x = 0;
442 prev_len++;
443 } else {
444 memmove(cmdline + cursor + 1, cmdline + cursor,
445 len - cursor + 1);
446 cmdline[cursor++] = key;
447 len++;
448 redraw = 1;
451 break;
455 printf("\033[?7h");
457 /* Add the command to the history */
458 comm_counter = malloc(sizeof(struct cli_command));
459 comm_counter->command = malloc(sizeof(char) * (strlen(ret) + 1));
460 strcpy(comm_counter->command, ret);
461 list_add(&(comm_counter->list), &cli_history_head);
463 return len ? ret : NULL;
466 static int __constructor cli_init(void)
468 INIT_LIST_HEAD(&cli_history_head);
470 return 0;
473 static void __destructor cli_exit(void)
475 /* Nothing to do */