source: mainline/uspace/app/bdsh/input.c@ 506cbf0

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

correcting comments according to coding guideline

  • Property mode set to 100644
File size: 9.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#include <adt/list.h>
48
49#include "config.h"
50#include "compl.h"
51#include "util.h"
52#include "scli.h"
53#include "input.h"
54#include "errors.h"
55#include "exec.h"
56#include "tok.h"
57
58extern volatile unsigned int cli_quit;
59
60/** Text input field. */
61static tinput_t *tinput;
62
63/* Private helpers */
64static int run_command(char **, cliuser_t *, iostate_t *);
65static void print_pipe_usage(void);
66
67typedef struct {
68 link_t alias_hup_link;
69 alias_t *alias;
70} alias_hup_t;
71
72static bool find_alias_hup(alias_t *alias, list_t *alias_hups)
73{
74 list_foreach(*alias_hups, alias_hup_link, alias_hup_t, link) {
75 if (alias == link->alias) {
76 return true;
77 }
78 }
79
80 return false;
81}
82
83/*
84 * Tokenizes input from console, sees if the first word is a built-in, if so
85 * invokes the built-in entry point (a[0]) passing all arguments in a[] to
86 * the handler
87 */
88static errno_t process_input_nohup(cliuser_t *usr, list_t *alias_hups)
89{
90 token_t *tokens_buf = calloc(WORD_MAX, sizeof(token_t));
91 if (tokens_buf == NULL)
92 return ENOMEM;
93 token_t *tokens = tokens_buf;
94
95 char *cmd[WORD_MAX];
96 errno_t rc = EOK;
97 tokenizer_t tok;
98 unsigned int i, pipe_count, processed_pipes;
99 unsigned int pipe_pos[2];
100 char *redir_from = NULL;
101 char *redir_to = NULL;
102
103 if (usr->line == NULL) {
104 free(tokens_buf);
105 return EINVAL;
106 }
107
108 rc = tok_init(&tok, usr->line, tokens, WORD_MAX);
109 if (rc != EOK) {
110 goto finit;
111 }
112
113 size_t tokens_length;
114 rc = tok_tokenize(&tok, &tokens_length);
115 if (rc != EOK) {
116 goto finit;
117 }
118
119 if (tokens_length > 0 && tokens[0].type == TOKTYPE_SPACE) {
120 tokens++;
121 tokens_length--;
122 }
123
124 if (tokens_length > 0 && tokens[tokens_length - 1].type == TOKTYPE_SPACE) {
125 tokens_length--;
126 }
127
128 /*
129 * Until full support for pipes is implemented, allow for a simple case:
130 * [from <file> |] command [| to <file>]
131 *
132 * First find the pipes and check that there are no more
133 */
134 for (i = 0, pipe_count = 0; i < tokens_length; i++) {
135 if (tokens[i].type == TOKTYPE_PIPE) {
136 if (pipe_count >= 2) {
137 print_pipe_usage();
138 rc = ENOTSUP;
139 goto finit;
140 }
141 pipe_pos[pipe_count] = i;
142 pipe_count++;
143 }
144 }
145
146 unsigned int cmd_token_start = 0;
147 unsigned int cmd_token_end = tokens_length;
148
149 processed_pipes = 0;
150
151 /* Check if the first part (from <file> |) is present */
152 if (pipe_count > 0 && (pipe_pos[0] == 3 || pipe_pos[0] == 4) && str_cmp(tokens[0].text, "from") == 0) {
153 /* Ignore the first three tokens (from, file, pipe) and set from */
154 redir_from = tokens[2].text;
155 cmd_token_start = pipe_pos[0] + 1;
156 processed_pipes++;
157 }
158
159 /* Check if the second part (| to <file>) is present */
160 if ((pipe_count - processed_pipes) > 0 &&
161 (pipe_pos[processed_pipes] == tokens_length - 4 ||
162 (pipe_pos[processed_pipes] == tokens_length - 5 &&
163 tokens[tokens_length - 4].type == TOKTYPE_SPACE)) &&
164 str_cmp(tokens[tokens_length - 3].text, "to") == 0) {
165 /* Ignore the last three tokens (pipe, to, file) and set to */
166 redir_to = tokens[tokens_length - 1].text;
167 cmd_token_end = pipe_pos[processed_pipes];
168 processed_pipes++;
169 }
170
171 if (processed_pipes != pipe_count) {
172 print_pipe_usage();
173 rc = ENOTSUP;
174 goto finit;
175 }
176
177 /* Convert tokens of the command to string array */
178 unsigned int cmd_pos = 0;
179 for (i = cmd_token_start; i < cmd_token_end; i++) {
180 if (tokens[i].type != TOKTYPE_SPACE) {
181 cmd[cmd_pos++] = tokens[i].text;
182 }
183 }
184 cmd[cmd_pos++] = NULL;
185
186 if (cmd[0] == NULL) {
187 print_pipe_usage();
188 rc = ENOTSUP;
189 goto finit;
190 }
191
192 /* test if the passed cmd is an alias */
193 odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)cmd[0], NULL);
194 if (alias_link != NULL) {
195 alias_t *data = odict_get_instance(alias_link, alias_t, odict);
196 /* check if the alias already has been resolved once */
197 if (!find_alias_hup(data, alias_hups)) {
198 alias_hup_t *hup = (alias_hup_t *)calloc(1, sizeof(hup));
199 hup->alias = data;
200 list_append(&hup->alias_hup_link, alias_hups);
201
202 char *oldLine = usr->line;
203 const size_t input_length = str_size(usr->line) - str_size(cmd[0]) + str_size(data->value) + 1;
204 usr->line = (char *)malloc(input_length * sizeof(char));
205 usr->line[0] = '\0';
206
207 unsigned int cmd_replace_index = cmd_token_start;
208 for (i = 0; i < tokens_length; i++) {
209 if (i == cmd_replace_index) {
210 /* if there is a pipe symbol than cmd_token_start will point at the SPACE after the pipe symbol */
211 if (tokens[i].type == TOKTYPE_SPACE) {
212 cmd_replace_index++;
213 str_append(usr->line, input_length, tokens[i].text);
214 continue;
215 }
216
217 str_append(usr->line, input_length, data->value);
218 } else {
219 str_append(usr->line, input_length, tokens[i].text);
220 }
221 }
222
223 /* reprocess input after string replace */
224 rc = process_input_nohup(usr, alias_hups);
225 usr->line = oldLine;
226 goto finit;
227 }
228 }
229
230 iostate_t new_iostate = {
231 .stdin = stdin,
232 .stdout = stdout,
233 .stderr = stderr
234 };
235
236 FILE *from = NULL;
237 FILE *to = NULL;
238
239 if (redir_from) {
240 from = fopen(redir_from, "r");
241 if (from == NULL) {
242 printf("Cannot open file %s\n", redir_from);
243 rc = errno;
244 goto finit_with_files;
245 }
246 new_iostate.stdin = from;
247 }
248
249 if (redir_to) {
250 to = fopen(redir_to, "w");
251 if (to == NULL) {
252 printf("Cannot open file %s\n", redir_to);
253 rc = errno;
254 goto finit_with_files;
255 }
256 new_iostate.stdout = to;
257 }
258
259 if (run_command(cmd, usr, &new_iostate) == 0) {
260 rc = EOK;
261 } else {
262 rc = EINVAL;
263 }
264
265finit_with_files:
266 if (from != NULL) {
267 fclose(from);
268 }
269 if (to != NULL) {
270 fclose(to);
271 }
272
273finit:
274 if (NULL != usr->line) {
275 free(usr->line);
276 usr->line = (char *) NULL;
277 }
278 tok_fini(&tok);
279 free(tokens_buf);
280
281 return rc;
282}
283
284errno_t process_input(cliuser_t *usr)
285{
286 list_t alias_hups;
287 list_initialize(&alias_hups);
288
289 errno_t rc = process_input_nohup(usr, &alias_hups);
290
291 list_foreach_safe(alias_hups, cur_link, next_link) {
292 alias_hup_t *cur_item = list_get_instance(cur_link, alias_hup_t, alias_hup_link);
293 free(cur_item);
294 }
295
296 return rc;
297}
298
299void print_pipe_usage(void)
300{
301 printf("Invalid syntax!\n");
302 printf("Usage of redirection (pipes in the future):\n");
303 printf("from filename | command ...\n");
304 printf("from filename | command ... | to filename\n");
305 printf("command ... | to filename\n");
306
307}
308
309int run_command(char **cmd, cliuser_t *usr, iostate_t *new_iostate)
310{
311 int id = 0;
312
313 /* We have rubbish */
314 if (NULL == cmd[0]) {
315 return CL_ENOENT;
316 }
317
318 /* Is it a builtin command ? */
319 if ((id = (is_builtin(cmd[0]))) > -1) {
320 return run_builtin(id, cmd, usr, new_iostate);
321 }
322
323 /* Is it a module ? */
324 if ((id = (is_module(cmd[0]))) > -1) {
325 return run_module(id, cmd, new_iostate);
326 }
327
328 /* See what try_exec thinks of it */
329 return try_exec(cmd[0], cmd, new_iostate);
330}
331
332void get_input(cliuser_t *usr)
333{
334 char *str;
335 errno_t rc;
336
337 tinput_set_prompt(tinput, usr->prompt);
338
339 rc = tinput_read(tinput, &str);
340 if (rc == ENOENT) {
341 /* User requested exit */
342 cli_quit = 1;
343 putchar('\n');
344 return;
345 }
346
347 if (rc != EOK) {
348 /* Error in communication with console */
349 cli_quit = 1;
350 return;
351 }
352
353 /* Check for empty input. */
354 if (str_cmp(str, "") == 0) {
355 free(str);
356 return;
357 }
358
359 usr->line = str;
360 return;
361}
362
363int input_init(void)
364{
365 tinput = tinput_new();
366 if (tinput == NULL) {
367 printf("Failed to initialize input.\n");
368 return 1;
369 }
370
371 tinput_set_compl_ops(tinput, &compl_ops);
372
373 return 0;
374}
Note: See TracBrowser for help on using the repository browser.