source: bootcd/isolinux/syslinux-6.03/com32/elflink/ldlinux/cli.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 9.3 KB
Line 
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>
17
18#include "getkey.h"
19#include "menu.h"
20#include "cli.h"
21#include "config.h"
22
23static struct list_head cli_history_head;
24
25void clear_screen(void)
26{
27    //dprintf("enter");
28    fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
29}
30
31static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto)
32{
33    clock_t t0, t1;
34    int key;
35
36    t0 = times(NULL);
37    key = get_key(stdin, *kbd_to ? *kbd_to : *tto);
38
39    /* kbdtimeout only applies to the first character */
40    if (*kbd_to)
41        *kbd_to = 0;
42
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;
52
53            *tto -= t1;
54        }
55    }
56
57    return key;
58}
59
60static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
61                                       clock_t *tto)
62{
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;
69
70    last_found = list_entry(cli_history_head.next, typeof(*last_found), list);
71
72    memset(buf, 0, MAX_CMDLINE_LEN);
73
74    printf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m");
75    while (1) {
76        key = mygetkey_timeout(kbd_to, tto);
77
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;
90        }
91
92        while (last_found) {
93            p = strstr(last_found->command, buf);
94            if (p)
95                break;
96
97            if (list_is_last(&last_found->list, &cli_history_head))
98                break;
99
100            last_found = list_entry(last_found->list.next, typeof(*last_found), list);
101        }
102
103        if (!p && !last_good) {
104            return NULL;
105        } else if (!p) {
106            continue;
107        } else {
108            last_good = last_found;
109            *cursor = p - last_good->command;
110        }
111
112        printf("\033[?7l\033[?25l");
113        /* Didn't handle the line wrap case here */
114        printf("\033[1G\033[1;36m(reverse-i-search)\033[0m`%s': %s",
115                buf, last_good->command ? : "");
116        printf("\033[K\r");
117    }
118
119    return last_good ? last_good->command : NULL;
120}
121
122
123
124const char *edit_cmdline(const char *input, int top /*, int width */ ,
125                         int (*pDraw_Menu) (int, int, int),
126                         void (*show_fkey) (int), bool *timedout)
127{
128    char cmdline[MAX_CMDLINE_LEN] = { };
129    int key, len, prev_len, cursor;
130    int redraw = 0;
131    int x, y;
132    bool done = false;
133    const char *ret;
134    int width = 0;
135    struct cli_command *comm_counter = NULL;
136    clock_t kbd_to = kbdtimeout;
137    clock_t tto = totaltimeout;
138
139    if (!width) {
140        int height;
141        if (getscreensize(1, &height, &width))
142            width = 80;
143    }
144
145    len = cursor = 0;
146    prev_len = 0;
147    x = y = 0;
148
149    /*
150     * Before we start messing with the x,y coordinates print 'input'
151     * so that it follows whatever text has been written to the screen
152     * previously.
153     */
154    printf("%s ", input);
155
156    while (!done) {
157        if (redraw > 1) {
158            /* Clear and redraw whole screen */
159            /* Enable ASCII on G0 and DEC VT on G1; do it in this order
160               to avoid confusing the Linux console */
161            clear_screen();
162            if (pDraw_Menu)
163                    (*pDraw_Menu) (-1, top, 1);
164            prev_len = 0;
165            printf("\033[2J\033[H");
166            // printf("\033[0m\033[2J\033[H");
167        }
168
169        if (redraw > 0) {
170            int dy, at;
171
172            prev_len = max(len, prev_len);
173
174            /* Redraw the command line */
175            printf("\033[?25l");
176            printf("\033[1G%s ", input);
177
178            x = strlen(input);
179            y = 0;
180            at = 0;
181            while (at < prev_len) {
182                putchar(at >= len ? ' ' : cmdline[at]);
183                at++;
184                x++;
185                if (x >= width) {
186                    printf("\r\n");
187                    x = 0;
188                    y++;
189                }
190            }
191            printf("\033[K\r");
192
193            dy = y - (cursor + strlen(input) + 1) / width;
194            x = (cursor + strlen(input) + 1) % width;
195
196            if (dy) {
197                printf("\033[%dA", dy);
198                y -= dy;
199            }
200            if (x)
201                printf("\033[%dC", x);
202            printf("\033[?25h");
203            prev_len = len;
204            redraw = 0;
205        }
206
207        key = mygetkey_timeout(&kbd_to, &tto);
208
209        switch (key) {
210        case KEY_NONE:
211            /* We timed out. */
212            *timedout = true;
213            return NULL;
214
215        case KEY_CTRL('L'):
216            redraw = 2;
217            break;
218
219        case KEY_ENTER:
220        case KEY_CTRL('J'):
221            ret = cmdline;
222            done = true;
223            break;
224
225        case KEY_BACKSPACE:
226        case KEY_DEL:
227            if (cursor) {
228                memmove(cmdline + cursor - 1, cmdline + cursor,
229                        len - cursor + 1);
230                len--;
231                cursor--;
232                redraw = 1;
233            }
234            break;
235
236        case KEY_CTRL('D'):
237        case KEY_DELETE:
238            if (cursor < len) {
239                memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
240                len--;
241                redraw = 1;
242            }
243            break;
244
245        case KEY_CTRL('U'):
246            if (len) {
247                len = cursor = 0;
248                cmdline[len] = '\0';
249                redraw = 1;
250            }
251            break;
252
253        case KEY_CTRL('W'):
254            if (cursor) {
255                int prevcursor = cursor;
256
257                while (cursor && my_isspace(cmdline[cursor - 1]))
258                    cursor--;
259
260                while (cursor && !my_isspace(cmdline[cursor - 1]))
261                    cursor--;
262
263#if 0
264                memmove(cmdline + cursor, cmdline + prevcursor,
265                        len - prevcursor + 1);
266#else
267                {
268                    int i;
269                    char *q = cmdline + cursor;
270                    char *p = cmdline + prevcursor;
271                    for (i = 0; i < len - prevcursor + 1; i++)
272                        *q++ = *p++;
273                }
274#endif
275                len -= (prevcursor - cursor);
276                redraw = 1;
277            }
278            break;
279
280        case KEY_LEFT:
281        case KEY_CTRL('B'):
282            if (cursor) {
283                cursor--;
284                redraw = 1;
285            }
286            break;
287
288        case KEY_RIGHT:
289        case KEY_CTRL('F'):
290            if (cursor < len) {
291                putchar(cmdline[cursor]);
292                cursor++;
293                x++;
294                if (x >= width) {
295                    printf("\r\n");
296                    y++;
297                    x = 0;
298                }
299            }
300            break;
301
302        case KEY_CTRL('K'):
303            if (cursor < len) {
304                cmdline[len = cursor] = '\0';
305                redraw = 1;
306            }
307            break;
308
309        case KEY_HOME:
310        case KEY_CTRL('A'):
311            if (cursor) {
312                cursor = 0;
313                redraw = 1;
314            }
315            break;
316
317        case KEY_END:
318        case KEY_CTRL('E'):
319            if (cursor != len) {
320                cursor = len;
321                redraw = 1;
322            }
323            break;
324
325        case KEY_F1:
326        case KEY_F2:
327        case KEY_F3:
328        case KEY_F4:
329        case KEY_F5:
330        case KEY_F6:
331        case KEY_F7:
332        case KEY_F8:
333        case KEY_F9:
334        case KEY_F10:
335        case KEY_F11:
336        case KEY_F12:
337            if (show_fkey != NULL) {
338                (*show_fkey) (key);
339                redraw = 1;
340            }
341            break;
342        case KEY_CTRL('P'):
343        case KEY_UP:
344            {
345                if (!list_empty(&cli_history_head)) {
346                    struct list_head *next;
347
348                    if (!comm_counter)
349                        next = cli_history_head.next;
350                    else
351                        next = comm_counter->list.next;
352
353                    comm_counter =
354                        list_entry(next, typeof(*comm_counter), list);
355
356                    if (&comm_counter->list != &cli_history_head)
357                        strcpy(cmdline, comm_counter->command);
358
359                    cursor = len = strlen(cmdline);
360                    redraw = 1;
361                }
362            }
363            break;
364        case KEY_CTRL('N'):
365        case KEY_DOWN:
366            {
367                if (!list_empty(&cli_history_head)) {
368                    struct list_head *prev;
369
370                    if (!comm_counter)
371                        prev = cli_history_head.prev;
372                    else
373                        prev = comm_counter->list.prev;
374
375                    comm_counter =
376                        list_entry(prev, typeof(*comm_counter), list);
377
378                    if (&comm_counter->list != &cli_history_head)
379                        strcpy(cmdline, comm_counter->command);
380
381                    cursor = len = strlen(cmdline);
382                    redraw = 1;
383                }
384            }
385            break;
386        case KEY_CTRL('R'):
387            {
388                 /*
389                  * Handle this case in another function, since it's
390                  * a kind of special.
391                  */
392                const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto);
393                if (p) {
394                    strcpy(cmdline, p);
395                    len = strlen(cmdline);
396                } else {
397                    cmdline[0] = '\0';
398                    cursor = len = 0;
399                }
400                redraw = 1;
401            }
402            break;
403        case KEY_TAB:
404            {
405                const char *p;
406                size_t len;
407
408                /* Label completion enabled? */
409                if (nocomplete)
410                    break;
411
412                p = cmdline;
413                len = 0;
414                while(*p && !my_isspace(*p)) {
415                    p++;
416                    len++;
417                }
418
419                print_labels(cmdline, len);
420                redraw = 1;
421                break;
422            }
423        case KEY_CTRL('V'):
424            if (BIOSName)
425                printf("%s%s%s", syslinux_banner,
426                       (char *)MK_PTR(0, BIOSName), copyright_str);
427            else
428                printf("%s%s", syslinux_banner, copyright_str);
429
430            redraw = 1;
431            break;
432
433        default:
434            if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
435                if (cursor == len) {
436                    cmdline[len++] = key;
437                    cmdline[len] = '\0';
438                    putchar(key);
439                    cursor++;
440                    x++;
441                    if (x >= width) {
442                        printf("\r\n\033[K");
443                        y++;
444                        x = 0;
445                    }
446                    prev_len++;
447                } else {
448                    if (cursor > len)
449                        return NULL;
450
451                    memmove(cmdline + cursor + 1, cmdline + cursor,
452                            len - cursor + 1);
453                    cmdline[cursor++] = key;
454                    len++;
455                    redraw = 1;
456                }
457            }
458            break;
459        }
460    }
461
462    printf("\033[?7h");
463
464    /* Add the command to the history if its length is larger than 0 */
465    len = strlen(ret);
466    if (len > 0) {
467        comm_counter = malloc(sizeof(struct cli_command));
468        comm_counter->command = malloc(sizeof(char) * (len + 1));
469        strcpy(comm_counter->command, ret);
470        list_add(&(comm_counter->list), &cli_history_head);
471    }
472
473    return len ? ret : NULL;
474}
475
476static int __constructor cli_init(void)
477{
478        INIT_LIST_HEAD(&cli_history_head);
479
480        return 0;
481}
482
483static void __destructor cli_exit(void)
484{
485        /* Nothing to do */
486}
Note: See TracBrowser for help on using the repository browser.