source: mainline/uspace/app/bdsh/input.c@ 598e3a7

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

implementing cmd replaces for alias

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