source: mainline/uspace/app/bdsh/input.c@ 4774a32

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4774a32 was da2bd08, checked in by Jiri Svoboda <jiri@…>, 16 years ago

Input history.

  • Property mode set to 100644
File size: 8.4 KB
RevLine 
[216d6fc]1/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
2 * All rights reserved.
3 * Copyright (c) 2008, Jiri Svoboda - All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * Neither the name of the original program's authors nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
[73878c1]35#include <io/console.h>
36#include <io/keycode.h>
37#include <io/style.h>
[3bf907a]38#include <vfs/vfs.h>
[6071a8f]39#include <errno.h>
[da2bd08]40#include <assert.h>
[6071a8f]41#include <bool.h>
[216d6fc]42
43#include "config.h"
44#include "util.h"
45#include "scli.h"
46#include "input.h"
47#include "errors.h"
48#include "exec.h"
49
[da2bd08]50#define HISTORY_LEN 10
51
[19528516]52typedef struct {
53 wchar_t buffer[INPUT_MAX];
54 int col0, row0;
55 int con_cols, con_rows;
56 int nc;
57 int pos;
[da2bd08]58
59 char *history[1 + HISTORY_LEN];
60 int hnum;
61 int hpos;
[19528516]62} tinput_t;
63
64typedef enum {
65 seek_backward = -1,
66 seek_forward = 1
67} seek_dir_t;
68
69static tinput_t tinput;
70
71static char *tinput_read(tinput_t *ti);
[88944695]72
[216d6fc]73/* Tokenizes input from console, sees if the first word is a built-in, if so
74 * invokes the built-in entry point (a[0]) passing all arguments in a[] to
75 * the handler */
76int tok_input(cliuser_t *usr)
77{
78 char *cmd[WORD_MAX];
79 int n = 0, i = 0;
80 int rc = 0;
81 char *tmp;
82
83 if (NULL == usr->line)
84 return CL_EFAIL;
85
[095003a8]86 tmp = str_dup(usr->line);
[216d6fc]87
[4cc0c9ee]88 cmd[n] = strtok(tmp, " ");
[216d6fc]89 while (cmd[n] && n < WORD_MAX) {
[4cc0c9ee]90 cmd[++n] = strtok(NULL, " ");
[216d6fc]91 }
92
93 /* We have rubbish */
94 if (NULL == cmd[0]) {
95 rc = CL_ENOENT;
96 goto finit;
97 }
98
[d752cf4]99 /* Its a builtin command ? */
[216d6fc]100 if ((i = (is_builtin(cmd[0]))) > -1) {
101 rc = run_builtin(i, cmd, usr);
102 goto finit;
[d752cf4]103 /* Its a module ? */
[216d6fc]104 } else if ((i = (is_module(cmd[0]))) > -1) {
105 rc = run_module(i, cmd);
106 goto finit;
107 }
108
[d752cf4]109 /* See what try_exec thinks of it */
110 rc = try_exec(cmd[0], cmd);
111
[216d6fc]112finit:
113 if (NULL != usr->line) {
114 free(usr->line);
115 usr->line = (char *) NULL;
116 }
117 if (NULL != tmp)
118 free(tmp);
119
120 return rc;
121}
122
[19528516]123static void tinput_display_tail(tinput_t *ti, int start, int pad)
124{
125 int i;
126
127 console_goto(fphone(stdout), ti->col0 + start, ti->row0);
128 printf("%ls", ti->buffer + start);
129 for (i = 0; i < pad; ++i)
130 putchar(' ');
131 fflush(stdout);
132}
133
[da2bd08]134static char *tinput_get_str(tinput_t *ti)
135{
136 char *str;
137
138 str = malloc(STR_BOUNDS(ti->nc) + 1);
139 if (str == NULL)
140 return NULL;
141
142 wstr_nstr(str, ti->buffer, STR_BOUNDS(ti->nc) + 1);
143
144 return str;
145}
146
[19528516]147static void tinput_position_caret(tinput_t *ti)
148{
149 console_goto(fphone(stdout), ti->col0 + ti->pos, ti->row0);
150}
151
152static void tinput_insert_char(tinput_t *ti, wchar_t c)
153{
154 int i;
155
156 if (ti->nc == INPUT_MAX)
157 return;
158
159 if (ti->col0 + ti->nc >= ti->con_cols - 1)
160 return;
161
162 for (i = ti->nc; i > ti->pos; --i)
163 ti->buffer[i] = ti->buffer[i - 1];
164
165 ti->buffer[ti->pos] = c;
166 ti->pos += 1;
167 ti->nc += 1;
168 ti->buffer[ti->nc] = '\0';
169
170 tinput_display_tail(ti, ti->pos - 1, 0);
171 tinput_position_caret(ti);
172}
173
174static void tinput_backspace(tinput_t *ti)
175{
176 int i;
177
178 if (ti->pos == 0)
179 return;
180
181 for (i = ti->pos; i < ti->nc; ++i)
182 ti->buffer[i - 1] = ti->buffer[i];
183 ti->pos -= 1;
184 ti->nc -= 1;
185 ti->buffer[ti->nc] = '\0';
186
187 tinput_display_tail(ti, ti->pos, 1);
188 tinput_position_caret(ti);
189}
190
191static void tinput_delete(tinput_t *ti)
192{
193 if (ti->pos == ti->nc)
194 return;
195
196 ti->pos += 1;
197 tinput_backspace(ti);
198}
199
[025759c]200static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir)
[19528516]201{
[025759c]202 if (dir == seek_forward) {
203 if (ti->pos < ti->nc)
204 ti->pos += 1;
205 } else {
206 if (ti->pos > 0)
207 ti->pos -= 1;
[19528516]208 }
[025759c]209
210 tinput_position_caret(ti);
211}
212
213static void tinput_seek_word(tinput_t *ti, seek_dir_t dir)
214{
215 if (dir == seek_forward) {
216 if (ti->pos == ti->nc)
217 return;
218
219 while (1) {
220 ti->pos += 1;
221
222 if (ti->pos == ti->nc)
223 break;
224
225 if (ti->buffer[ti->pos - 1] == ' ' &&
226 ti->buffer[ti->pos] != ' ')
227 break;
228 }
229 } else {
230 if (ti->pos == 0)
231 return;
232
233 while (1) {
234 ti->pos -= 1;
235
236 if (ti->pos == 0)
237 break;
238
239 if (ti->buffer[ti->pos - 1] == ' ' &&
240 ti->buffer[ti->pos] != ' ')
241 break;
242 }
243
244 }
245
246 tinput_position_caret(ti);
247}
248
249static void tinput_seek_max(tinput_t *ti, seek_dir_t dir)
250{
251 if (dir == seek_backward)
252 ti->pos = 0;
253 else
254 ti->pos = ti->nc;
[19528516]255
256 tinput_position_caret(ti);
257}
258
[da2bd08]259static void tinput_history_insert(tinput_t *ti, char *str)
260{
261 int i;
262
263 if (ti->hnum < HISTORY_LEN) {
264 ti->hnum += 1;
265 } else {
266 if (ti->history[HISTORY_LEN] != NULL)
267 free(ti->history[HISTORY_LEN]);
268 }
269
270 for (i = ti->hnum; i > 1; --i)
271 ti->history[i] = ti->history[i - 1];
272
273 ti->history[1] = str_dup(str);
274
275 if (ti->history[0] != NULL) {
276 free(ti->history[0]);
277 ti->history[0] = NULL;
278 }
279}
280
281static void tinput_set_str(tinput_t *ti, char *str)
282{
283 str_to_wstr(ti->buffer, INPUT_MAX, str);
284 ti->nc = wstr_length(ti->buffer);
285 ti->pos = ti->nc;
286}
287
288static void tinput_history_seek(tinput_t *ti, int offs)
289{
290 int pad;
291
292 if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum)
293 return;
294
295 if (ti->history[ti->hpos] != NULL) {
296 free(ti->history[ti->hpos]);
297 ti->history[ti->hpos] = NULL;
298 }
299
300 ti->history[ti->hpos] = tinput_get_str(ti);
301 ti->hpos += offs;
302
303 pad = ti->nc - str_length(ti->history[ti->hpos]);
304 if (pad < 0) pad = 0;
305
306 tinput_set_str(ti, ti->history[ti->hpos]);
307 tinput_display_tail(ti, 0, pad);
308 tinput_position_caret(ti);
309}
310
311static void tinput_init(tinput_t *ti)
312{
313 ti->hnum = 0;
314 ti->hpos = 0;
315 ti->history[0] = NULL;
316}
317
[19528516]318static char *tinput_read(tinput_t *ti)
[216d6fc]319{
[73878c1]320 console_event_t ev;
[19528516]321 char *str;
322
323 fflush(stdout);
324
325 if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
326 return NULL;
327 if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
328 return NULL;
329
330 ti->pos = 0;
331 ti->nc = 0;
[216d6fc]332
[6071a8f]333 while (true) {
[56fa418]334 fflush(stdout);
[73878c1]335 if (!console_get_event(fphone(stdin), &ev))
[19528516]336 return NULL;
[73878c1]337
338 if (ev.type != KEY_PRESS)
[56fa418]339 continue;
[19528516]340
[025759c]341 if ((ev.mods & KM_CTRL) != 0 &&
342 (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {
343 switch (ev.key) {
344 case KC_LEFT:
345 tinput_seek_word(ti, seek_backward);
346 break;
347 case KC_RIGHT:
348 tinput_seek_word(ti, seek_forward);
349 break;
350 }
351 }
[19528516]352
[025759c]353 if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
354 switch (ev.key) {
355 case KC_ENTER:
356 case KC_NENTER:
357 goto done;
358 case KC_BACKSPACE:
359 tinput_backspace(ti);
360 break;
361 case KC_DELETE:
362 tinput_delete(ti);
363 break;
364 case KC_LEFT:
365 tinput_seek_cell(ti, seek_backward);
366 break;
367 case KC_RIGHT:
368 tinput_seek_cell(ti, seek_forward);
369 break;
370 case KC_HOME:
371 tinput_seek_max(ti, seek_backward);
372 break;
373 case KC_END:
374 tinput_seek_max(ti, seek_forward);
375 break;
[da2bd08]376 case KC_UP:
377 tinput_history_seek(ti, +1);
378 break;
379 case KC_DOWN:
380 tinput_history_seek(ti, -1);
381 break;
[025759c]382 }
[216d6fc]383 }
[025759c]384
[56fa418]385 if (ev.c >= ' ') {
[19528516]386 tinput_insert_char(ti, ev.c);
[38c64e8]387 }
[216d6fc]388 }
[19528516]389
390done:
[216d6fc]391 putchar('\n');
[19528516]392
[da2bd08]393 str = tinput_get_str(ti);
394 if (str_cmp(str, "") != 0)
395 tinput_history_insert(ti, str);
[19528516]396
[da2bd08]397 ti->hpos = 0;
[19528516]398
399 return str;
[216d6fc]400}
401
402void get_input(cliuser_t *usr)
403{
[19528516]404 char *str;
[216d6fc]405
[ef8bcc6]406 fflush(stdout);
[73878c1]407 console_set_style(fphone(stdout), STYLE_EMPHASIS);
[216d6fc]408 printf("%s", usr->prompt);
[ef8bcc6]409 fflush(stdout);
[73878c1]410 console_set_style(fphone(stdout), STYLE_NORMAL);
[9805cde]411
[19528516]412 str = tinput_read(&tinput);
413
414 /* Check for empty input. */
415 if (str_cmp(str, "") == 0) {
416 free(str);
[216d6fc]417 return;
[19528516]418 }
[216d6fc]419
[19528516]420 usr->line = str;
[216d6fc]421 return;
422}
[da2bd08]423
424void input_init(void)
425{
426 tinput_init(&tinput);
427}
Note: See TracBrowser for help on using the repository browser.