]> code.delx.au - refind/blob - refind/line_edit.c
Modified SIP/CSR feature to work ON MACS when the csr-active-config
[refind] / refind / line_edit.c
1 // Line-editing functions borrowed from gummiboot (cursor_left(),
2 // cursor_right(), & line_edit()).
3
4 /*
5 * Simple UEFI boot loader which executes configured EFI images, where the
6 * default entry is selected by a configured pattern (glob) or an on-screen
7 * menu.
8 *
9 * All gummiboot code is LGPL not GPL, to stay out of politics and to give
10 * the freedom of copying code from programs to possible future libraries.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 *
22 * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
23 * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
24 *
25 * "Any intelligent fool can make things bigger, more complex, and more violent.
26 "
27 * -- Albert Einstein
28 */
29
30 #include "global.h"
31 #include "screen.h"
32 #include "lib.h"
33 #include "../include/refit_call_wrapper.h"
34
35 static void cursor_left(UINTN *cursor, UINTN *first)
36 {
37 if ((*cursor) > 0)
38 (*cursor)--;
39 else if ((*first) > 0)
40 (*first)--;
41 }
42
43 static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
44 {
45 if ((*cursor)+2 < x_max)
46 (*cursor)++;
47 else if ((*first) + (*cursor) < len)
48 (*first)++;
49 }
50
51 BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max) {
52 CHAR16 *line;
53 UINTN size;
54 UINTN len;
55 UINTN first;
56 UINTN y_pos = 3;
57 CHAR16 *print;
58 UINTN cursor;
59 BOOLEAN exit;
60 BOOLEAN enter;
61
62 DrawScreenHeader(L"Line Editor");
63 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, (ConWidth - 71) / 2, ConHeight - 1);
64 refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut,
65 L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options");
66
67 if (!line_in)
68 line_in = L"";
69 size = StrLen(line_in) + 1024;
70 line = AllocatePool(size * sizeof(CHAR16));
71 StrCpy(line, line_in);
72 len = StrLen(line);
73 print = AllocatePool(x_max * sizeof(CHAR16));
74
75 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
76
77 first = 0;
78 cursor = 0;
79 enter = FALSE;
80 exit = FALSE;
81 while (!exit) {
82 UINTN index;
83 EFI_STATUS err;
84 EFI_INPUT_KEY key;
85 UINTN i;
86
87 i = len - first;
88 if (i >= x_max-2)
89 i = x_max-2;
90 CopyMem(print, line + first, i * sizeof(CHAR16));
91 print[i++] = ' ';
92 print[i] = '\0';
93
94 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos);
95 refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print);
96 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
97
98 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
99 err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
100 if (EFI_ERROR(err))
101 continue;
102
103 switch (key.ScanCode) {
104 case SCAN_ESC:
105 exit = TRUE;
106 break;
107 case SCAN_HOME:
108 cursor = 0;
109 first = 0;
110 continue;
111 case SCAN_END:
112 cursor = len;
113 if (cursor >= x_max) {
114 cursor = x_max-2;
115 first = len - (x_max-2);
116 }
117 continue;
118 case SCAN_UP:
119 while((first + cursor) && line[first + cursor] == ' ')
120 cursor_left(&cursor, &first);
121 while((first + cursor) && line[first + cursor] != ' ')
122 cursor_left(&cursor, &first);
123 while((first + cursor) && line[first + cursor] == ' ')
124 cursor_left(&cursor, &first);
125 if (first + cursor != len && first + cursor)
126 cursor_right(&cursor, &first, x_max, len);
127 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
128 continue;
129 case SCAN_DOWN:
130 while(line[first + cursor] && line[first + cursor] == ' ')
131 cursor_right(&cursor, &first, x_max, len);
132 while(line[first + cursor] && line[first + cursor] != ' ')
133 cursor_right(&cursor, &first, x_max, len);
134 while(line[first + cursor] && line[first + cursor] == ' ')
135 cursor_right(&cursor, &first, x_max, len);
136 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
137 continue;
138 case SCAN_RIGHT:
139 if (first + cursor == len)
140 continue;
141 cursor_right(&cursor, &first, x_max, len);
142 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
143 continue;
144 case SCAN_LEFT:
145 cursor_left(&cursor, &first);
146 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
147 continue;
148 case SCAN_DELETE:
149 if (len == 0)
150 continue;
151 if (first + cursor == len)
152 continue;
153 for (i = first + cursor; i < len; i++)
154 line[i] = line[i+1];
155 line[len-1] = ' ';
156 len--;
157 continue;
158 }
159
160 switch (key.UnicodeChar) {
161 case CHAR_LINEFEED:
162 case CHAR_CARRIAGE_RETURN:
163 *line_out = line;
164 line = NULL;
165 enter = TRUE;
166 exit = TRUE;
167 break;
168 case CHAR_BACKSPACE:
169 if (len == 0)
170 continue;
171 if (first == 0 && cursor == 0)
172 continue;
173 for (i = first + cursor-1; i < len; i++)
174 line[i] = line[i+1];
175 len--;
176 if (cursor > 0)
177 cursor--;
178 if (cursor > 0 || first == 0)
179 continue;
180 /* show full line if it fits */
181 if (len < x_max-2) {
182 cursor = first;
183 first = 0;
184 continue;
185 }
186 /* jump left to see what we delete */
187 if (first > 10) {
188 first -= 10;
189 cursor = 10;
190 } else {
191 cursor = first;
192 first = 0;
193 }
194 continue;
195 case '\t':
196 case ' ' ... '~':
197 case 0x80 ... 0xffff:
198 if (len+1 == size)
199 continue;
200 for (i = len; i > first + cursor; i--)
201 line[i] = line[i-1];
202 line[first + cursor] = key.UnicodeChar;
203 len++;
204 line[len] = '\0';
205 if (cursor+2 < x_max)
206 cursor++;
207 else if (first + cursor < len)
208 first++;
209 continue;
210 }
211 }
212
213 refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
214 FreePool(print);
215 FreePool(line);
216 return enter;
217 } /* BOOLEAN line_edit() */