source: mainline/uspace/app/bdsh/input.c@ c916dfc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c916dfc was 5fb32c5, checked in by Petr Koupy <petr.koupy@…>, 14 years ago

Merge mainline changes.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2008 Tim Post
3 * Copyright (c) 2011 Jiri Svoboda
4 * Copyright (c) 2011 Martin Sucha
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <str.h>
34#include <io/console.h>
35#include <io/keycode.h>
36#include <io/style.h>
37#include <io/color.h>
38#include <vfs/vfs.h>
39#include <clipboard.h>
40#include <macros.h>
41#include <errno.h>
42#include <assert.h>
43#include <bool.h>
44#include <tinput.h>
45
46#include "config.h"
47#include "compl.h"
48#include "util.h"
49#include "scli.h"
50#include "input.h"
51#include "errors.h"
52#include "exec.h"
53#include "tok.h"
54
55extern volatile unsigned int cli_quit;
56
57/** Text input field. */
58static tinput_t *tinput;
59
60/* Private helpers */
61static int run_command(char **, cliuser_t *, iostate_t *);
62static void print_pipe_usage(void);
63
64/* Tokenizes input from console, sees if the first word is a built-in, if so
65 * invokes the built-in entry point (a[0]) passing all arguments in a[] to
66 * the handler */
67int process_input(cliuser_t *usr)
68{
69 char *cmd[WORD_MAX];
70 token_t tokens_space[WORD_MAX];
71 token_t *tokens = tokens_space;
72 int rc = 0;
73 tokenizer_t tok;
74 unsigned int i, pipe_count, processed_pipes;
75 unsigned int pipe_pos[2];
76 char *redir_from = NULL;
77 char *redir_to = NULL;
78
79 if (NULL == usr->line)
80 return CL_EFAIL;
81
82 rc = tok_init(&tok, usr->line, tokens, WORD_MAX);
83 if (rc != EOK) {
84 goto finit;
85 }
86
87 size_t tokens_length;
88 rc = tok_tokenize(&tok, &tokens_length);
89 if (rc != EOK) {
90 goto finit;
91 }
92
93 if (tokens_length > 0 && tokens[0].type == TOKTYPE_SPACE) {
94 tokens++;
95 tokens_length--;
96 }
97
98 if (tokens_length > 0 && tokens[tokens_length-1].type == TOKTYPE_SPACE) {
99 tokens_length--;
100 }
101
102 /* Until full support for pipes is implemented, allow for a simple case:
103 * [from <file> |] command [| to <file>]
104 *
105 * First find the pipes and check that there are no more
106 */
107 for (i = 0, pipe_count = 0; i < tokens_length; i++) {
108 if (tokens[i].type == TOKTYPE_PIPE) {
109 if (pipe_count >= 2) {
110 print_pipe_usage();
111 rc = ENOTSUP;
112 goto finit;
113 }
114 pipe_pos[pipe_count] = i;
115 pipe_count++;
116 }
117 }
118
119 unsigned int cmd_token_start = 0;
120 unsigned int cmd_token_end = tokens_length;
121
122 processed_pipes = 0;
123
124 /* Check if the first part (from <file> |) is present */
125 if (pipe_count > 0 && (pipe_pos[0] == 3 || pipe_pos[0] == 4) && str_cmp(tokens[0].text, "from") == 0) {
126 /* Ignore the first three tokens (from, file, pipe) and set from */
127 redir_from = tokens[2].text;
128 cmd_token_start = pipe_pos[0]+1;
129 processed_pipes++;
130 }
131
132 /* Check if the second part (| to <file>) is present */
133 if ((pipe_count - processed_pipes) > 0 &&
134 (pipe_pos[processed_pipes] == tokens_length - 4 ||
135 (pipe_pos[processed_pipes] == tokens_length - 5 &&
136 tokens[tokens_length-4].type == TOKTYPE_SPACE )) &&
137 str_cmp(tokens[tokens_length-3].text, "to") == 0) {
138 /* Ignore the last three tokens (pipe, to, file) and set to */
139 redir_to = tokens[tokens_length-1].text;
140 cmd_token_end = pipe_pos[processed_pipes];
141 processed_pipes++;
142 }
143
144 if (processed_pipes != pipe_count) {
145 print_pipe_usage();
146 rc = ENOTSUP;
147 goto finit;
148 }
149
150 /* Convert tokens of the command to string array */
151 unsigned int cmd_pos = 0;
152 for (i = cmd_token_start; i < cmd_token_end; i++) {
153 if (tokens[i].type != TOKTYPE_SPACE) {
154 cmd[cmd_pos++] = tokens[i].text;
155 }
156 }
157 cmd[cmd_pos++] = NULL;
158
159 if (cmd[0] == NULL) {
160 print_pipe_usage();
161 rc = ENOTSUP;
162 goto finit;
163 }
164
165 iostate_t new_iostate = {
166 .stdin = stdin,
167 .stdout = stdout,
168 .stderr = stderr
169 };
170
171 FILE *from = NULL;
172 FILE *to = NULL;
173
174 if (redir_from) {
175 from = fopen(redir_from, "r");
176 if (from == NULL) {
177 printf("Cannot open file %s\n", redir_from);
178 rc = errno;
179 goto finit_with_files;
180 }
181 new_iostate.stdin = from;
182 }
183
184
185 if (redir_to) {
186 to = fopen(redir_to, "w");
187 if (to == NULL) {
188 printf("Cannot open file %s\n", redir_to);
189 rc = errno;
190 goto finit_with_files;
191 }
192 new_iostate.stdout = to;
193 }
194
195 if (str_cmp(cmd[0], "batch") == 0 && cmd[1] != NULL) {
196 FILE *batch = fopen(cmd[1], "r");
197 if (batch == NULL) {
198 printf("Cannot open file %s\n", cmd[1]);
199 rc = errno;
200 } else {
201 cliuser_t fusr;
202 fusr.name = usr->name;
203 fusr.cwd = usr->cwd;
204 fusr.prompt = usr->prompt;
205 fusr.line = malloc(INPUT_MAX + 1);
206 char *cur = fusr.line;
207 char *end = fusr.line + INPUT_MAX;
208 int c = fgetc(batch);
209 while (fusr.line != NULL) {
210 if (c == '\n' || c == EOF || cur == end) {
211 *cur = '\0';
212 if (cur == fusr.line) {
213 /* skip empty line */
214 rc = 0;
215 free(cur);
216 } else {
217 printf(">%s\n", fusr.line);
218 rc = process_input(&fusr);
219 /* fusr->line was freed by process_input() */
220 }
221 if (rc == 0 && c != EOF) {
222 fusr.line = malloc(INPUT_MAX + 1);
223 cur = fusr.line;
224 end = fusr.line + INPUT_MAX;
225 } else {
226 break;
227 }
228 } else {
229 *cur++ = c;
230 }
231 c = fgetc(batch);
232 }
233 fclose(batch);
234 }
235 } else {
236 rc = run_command(cmd, usr, &new_iostate);
237 }
238
239finit_with_files:
240 if (from != NULL) {
241 fclose(from);
242 }
243 if (to != NULL) {
244 fclose(to);
245 }
246
247finit:
248 if (NULL != usr->line) {
249 free(usr->line);
250 usr->line = (char *) NULL;
251 }
252 tok_fini(&tok);
253
254 return rc;
255}
256
257void print_pipe_usage()
258{
259 printf("Invalid syntax!\n");
260 printf("Usage of redirection (pipes in the future):\n");
261 printf("from filename | command ...\n");
262 printf("from filename | command ... | to filename\n");
263 printf("command ... | to filename\n");
264
265}
266
267int run_command(char **cmd, cliuser_t *usr, iostate_t *new_iostate)
268{
269 int id = 0;
270
271 /* We have rubbish */
272 if (NULL == cmd[0]) {
273 return CL_ENOENT;
274 }
275
276 /* Is it a builtin command ? */
277 if ((id = (is_builtin(cmd[0]))) > -1) {
278 return run_builtin(id, cmd, usr, new_iostate);
279 }
280
281 /* Is it a module ? */
282 if ((id = (is_module(cmd[0]))) > -1) {
283 return run_module(id, cmd, new_iostate);
284 }
285
286 /* See what try_exec thinks of it */
287 return try_exec(cmd[0], cmd, new_iostate);
288}
289
290void get_input(cliuser_t *usr)
291{
292 char *str;
293 int rc;
294
295 tinput_set_prompt(tinput, usr->prompt);
296
297 rc = tinput_read(tinput, &str);
298 if (rc == ENOENT) {
299 /* User requested exit */
300 cli_quit = 1;
301 putchar('\n');
302 return;
303 }
304
305 if (rc != EOK) {
306 /* Error in communication with console */
307 return;
308 }
309
310 /* Check for empty input. */
311 if (str_cmp(str, "") == 0) {
312 free(str);
313 return;
314 }
315
316 usr->line = str;
317 return;
318}
319
320int input_init(void)
321{
322 tinput = tinput_new();
323 if (tinput == NULL) {
324 printf("Failed to initialize input.\n");
325 return 1;
326 }
327
328 tinput_set_compl_ops(tinput, &compl_ops);
329
330 return 0;
331}
Note: See TracBrowser for help on using the repository browser.