source: mainline/uspace/app/bdsh/input.c@ 25c1b2c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 25c1b2c was b9ae539, checked in by Martin Sucha <sucha14@…>, 14 years ago

Allocate space for tokens on the heap as it is too large for a stack (thx Petr Koupy)

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[36ab7c7]1/*
2 * Copyright (c) 2008 Tim Post
[9be9c4d]3 * Copyright (c) 2011 Jiri Svoboda
[b2727f18]4 * Copyright (c) 2011 Martin Sucha
[216d6fc]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
[36ab7c7]8 * modification, are permitted provided that the following conditions
9 * are met:
[216d6fc]10 *
[36ab7c7]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.
[216d6fc]18 *
[36ab7c7]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.
[216d6fc]29 */
30
31#include <stdio.h>
32#include <stdlib.h>
[19f857a]33#include <str.h>
[73878c1]34#include <io/console.h>
35#include <io/keycode.h>
36#include <io/style.h>
[7e0cb78]37#include <io/color.h>
[3bf907a]38#include <vfs/vfs.h>
[371a012]39#include <clipboard.h>
[f1b37d6]40#include <macros.h>
[6071a8f]41#include <errno.h>
[da2bd08]42#include <assert.h>
[6071a8f]43#include <bool.h>
[36a75a2]44#include <tinput.h>
[216d6fc]45
46#include "config.h"
[9be9c4d]47#include "compl.h"
[216d6fc]48#include "util.h"
49#include "scli.h"
50#include "input.h"
51#include "errors.h"
52#include "exec.h"
[6939edb]53#include "tok.h"
[216d6fc]54
[5db9084]55extern volatile unsigned int cli_quit;
56
[ed372da]57/** Text input field. */
[36a75a2]58static tinput_t *tinput;
[88944695]59
[6939edb]60/* Private helpers */
[6ea9a1d]61static int run_command(char **, cliuser_t *, iostate_t *);
[ae45201]62static void print_pipe_usage(void);
[659e9473]63
[216d6fc]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 */
[28ee877e]67int process_input(cliuser_t *usr)
[216d6fc]68{
69 char *cmd[WORD_MAX];
[b9ae539]70 token_t *tokens = calloc(WORD_MAX, sizeof(token_t));
71 if (tokens == NULL)
72 return ENOMEM;
[216d6fc]73 int rc = 0;
[6939edb]74 tokenizer_t tok;
[0662451]75 unsigned int i, pipe_count, processed_pipes;
76 unsigned int pipe_pos[2];
[ae45201]77 char *redir_from = NULL;
78 char *redir_to = NULL;
[216d6fc]79
[b9ae539]80 if (NULL == usr->line) {
81 free(tokens);
[216d6fc]82 return CL_EFAIL;
[b9ae539]83 }
[216d6fc]84
[0662451]85 rc = tok_init(&tok, usr->line, tokens, WORD_MAX);
[6939edb]86 if (rc != EOK) {
87 goto finit;
[216d6fc]88 }
[6939edb]89
[0662451]90 size_t tokens_length;
91 rc = tok_tokenize(&tok, &tokens_length);
[6939edb]92 if (rc != EOK) {
93 goto finit;
94 }
95
[0662451]96 if (tokens_length > 0 && tokens[0].type == TOKTYPE_SPACE) {
97 tokens++;
98 tokens_length--;
99 }
100
101 if (tokens_length > 0 && tokens[tokens_length-1].type == TOKTYPE_SPACE) {
102 tokens_length--;
103 }
104
[ae45201]105 /* Until full support for pipes is implemented, allow for a simple case:
106 * [from <file> |] command [| to <file>]
107 *
108 * First find the pipes and check that there are no more
109 */
[0662451]110 for (i = 0, pipe_count = 0; i < tokens_length; i++) {
111 if (tokens[i].type == TOKTYPE_PIPE) {
[ae45201]112 if (pipe_count >= 2) {
113 print_pipe_usage();
114 rc = ENOTSUP;
115 goto finit;
116 }
117 pipe_pos[pipe_count] = i;
118 pipe_count++;
119 }
120 }
121
[0662451]122 unsigned int cmd_token_start = 0;
123 unsigned int cmd_token_end = tokens_length;
124
[ae45201]125 processed_pipes = 0;
126
127 /* Check if the first part (from <file> |) is present */
[0662451]128 if (pipe_count > 0 && (pipe_pos[0] == 3 || pipe_pos[0] == 4) && str_cmp(tokens[0].text, "from") == 0) {
[ae45201]129 /* Ignore the first three tokens (from, file, pipe) and set from */
[0662451]130 redir_from = tokens[2].text;
131 cmd_token_start = pipe_pos[0]+1;
[ae45201]132 processed_pipes++;
133 }
134
135 /* Check if the second part (| to <file>) is present */
136 if ((pipe_count - processed_pipes) > 0 &&
[0662451]137 (pipe_pos[processed_pipes] == tokens_length - 4 ||
138 (pipe_pos[processed_pipes] == tokens_length - 5 &&
139 tokens[tokens_length-4].type == TOKTYPE_SPACE )) &&
140 str_cmp(tokens[tokens_length-3].text, "to") == 0) {
[ae45201]141 /* Ignore the last three tokens (pipe, to, file) and set to */
[0662451]142 redir_to = tokens[tokens_length-1].text;
143 cmd_token_end = pipe_pos[processed_pipes];
[ae45201]144 processed_pipes++;
145 }
146
147 if (processed_pipes != pipe_count) {
148 print_pipe_usage();
149 rc = ENOTSUP;
150 goto finit;
151 }
152
[0662451]153 /* Convert tokens of the command to string array */
154 unsigned int cmd_pos = 0;
155 for (i = cmd_token_start; i < cmd_token_end; i++) {
156 if (tokens[i].type != TOKTYPE_SPACE) {
157 cmd[cmd_pos++] = tokens[i].text;
158 }
159 }
160 cmd[cmd_pos++] = NULL;
161
162 if (cmd[0] == NULL) {
[ae45201]163 print_pipe_usage();
164 rc = ENOTSUP;
165 goto finit;
166 }
167
[6ea9a1d]168 iostate_t new_iostate = {
169 .stdin = stdin,
170 .stdout = stdout,
171 .stderr = stderr
172 };
173
174 FILE *from = NULL;
175 FILE *to = NULL;
[ae45201]176
177 if (redir_from) {
[6ea9a1d]178 from = fopen(redir_from, "r");
[ae45201]179 if (from == NULL) {
180 printf("Cannot open file %s\n", redir_from);
181 rc = errno;
[6ea9a1d]182 goto finit_with_files;
[ae45201]183 }
[6ea9a1d]184 new_iostate.stdin = from;
[ae45201]185 }
186
[6ea9a1d]187
[ae45201]188 if (redir_to) {
[6ea9a1d]189 to = fopen(redir_to, "w");
[ae45201]190 if (to == NULL) {
191 printf("Cannot open file %s\n", redir_to);
192 rc = errno;
[6ea9a1d]193 goto finit_with_files;
[ae45201]194 }
[6ea9a1d]195 new_iostate.stdout = to;
[ae45201]196 }
197
[0662451]198 rc = run_command(cmd, usr, &new_iostate);
[6ea9a1d]199
200finit_with_files:
201 if (from != NULL) {
202 fclose(from);
203 }
204 if (to != NULL) {
205 fclose(to);
206 }
[6939edb]207
208finit:
[216d6fc]209 if (NULL != usr->line) {
210 free(usr->line);
211 usr->line = (char *) NULL;
212 }
[6939edb]213 tok_fini(&tok);
[b9ae539]214 free(tokens);
[216d6fc]215
216 return rc;
217}
218
[ae45201]219void print_pipe_usage()
220{
221 printf("Invalid syntax!\n");
222 printf("Usage of redirection (pipes in the future):\n");
223 printf("from filename | command ...\n");
224 printf("from filename | command ... | to filename\n");
225 printf("command ... | to filename\n");
226
227}
228
[6ea9a1d]229int run_command(char **cmd, cliuser_t *usr, iostate_t *new_iostate)
[659e9473]230{
231 int id = 0;
232
233 /* We have rubbish */
234 if (NULL == cmd[0]) {
235 return CL_ENOENT;
236 }
237
238 /* Is it a builtin command ? */
239 if ((id = (is_builtin(cmd[0]))) > -1) {
[6ea9a1d]240 return run_builtin(id, cmd, usr, new_iostate);
[659e9473]241 }
242
243 /* Is it a module ? */
244 if ((id = (is_module(cmd[0]))) > -1) {
[6ea9a1d]245 return run_module(id, cmd, new_iostate);
[659e9473]246 }
247
248 /* See what try_exec thinks of it */
[6ea9a1d]249 return try_exec(cmd[0], cmd, new_iostate);
[659e9473]250}
251
[216d6fc]252void get_input(cliuser_t *usr)
253{
[19528516]254 char *str;
[5db9084]255 int rc;
[79ae36dd]256
[9be9c4d]257 tinput_set_prompt(tinput, usr->prompt);
[9805cde]258
[5db9084]259 rc = tinput_read(tinput, &str);
260 if (rc == ENOENT) {
261 /* User requested exit */
262 cli_quit = 1;
263 putchar('\n');
264 return;
265 }
266
267 if (rc != EOK) {
268 /* Error in communication with console */
269 return;
270 }
[19528516]271
272 /* Check for empty input. */
273 if (str_cmp(str, "") == 0) {
274 free(str);
[216d6fc]275 return;
[19528516]276 }
[216d6fc]277
[19528516]278 usr->line = str;
[216d6fc]279 return;
280}
[da2bd08]281
[36a75a2]282int input_init(void)
[da2bd08]283{
[36a75a2]284 tinput = tinput_new();
285 if (tinput == NULL) {
286 printf("Failed to initialize input.\n");
287 return 1;
288 }
289
[9be9c4d]290 tinput_set_compl_ops(tinput, &compl_ops);
291
[36a75a2]292 return 0;
[da2bd08]293}
Note: See TracBrowser for help on using the repository browser.