source: mainline/uspace/app/bdsh/input.c@ 63087f1d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63087f1d was 63087f1d, checked in by Matthieu Riolo <matthieu.riolo@…>, 7 years ago

adding copyrights

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