source: mainline/uspace/app/bdsh/input.c@ 6ea9a1d

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

Allow shell builtins to be redirected too

  • Property mode set to 100644
File size: 6.2 KB
Line 
1/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of the original program's authors nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * 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 "util.h"
48#include "scli.h"
49#include "input.h"
50#include "errors.h"
51#include "exec.h"
52#include "tok.h"
53
54extern volatile unsigned int cli_quit;
55
56/** Text input field. */
57static tinput_t *tinput;
58
59/* Private helpers */
60static int run_command(char **, cliuser_t *, iostate_t *);
61static void print_pipe_usage(void);
62
63/* Tokenizes input from console, sees if the first word is a built-in, if so
64 * invokes the built-in entry point (a[0]) passing all arguments in a[] to
65 * the handler */
66int process_input(cliuser_t *usr)
67{
68 char *cmd[WORD_MAX];
69 int rc = 0;
70 tokenizer_t tok;
71 int i, pipe_count, processed_pipes;
72 int pipe_pos[2];
73 char **actual_cmd;
74 char *redir_from = NULL;
75 char *redir_to = NULL;
76
77 if (NULL == usr->line)
78 return CL_EFAIL;
79
80 rc = tok_init(&tok, usr->line, cmd, WORD_MAX);
81 if (rc != EOK) {
82 goto finit;
83 }
84
85 rc = tok_tokenize(&tok);
86 if (rc != EOK) {
87 goto finit;
88 }
89
90 /* Until full support for pipes is implemented, allow for a simple case:
91 * [from <file> |] command [| to <file>]
92 *
93 * First find the pipes and check that there are no more
94 */
95 int cmd_length = 0;
96 for (i = 0, pipe_count = 0; cmd[i] != NULL; i++, cmd_length++) {
97 if (cmd[i][0] == '|') {
98 if (pipe_count >= 2) {
99 print_pipe_usage();
100 rc = ENOTSUP;
101 goto finit;
102 }
103 pipe_pos[pipe_count] = i;
104 pipe_count++;
105 }
106 }
107
108 actual_cmd = cmd;
109 processed_pipes = 0;
110
111 /* Check if the first part (from <file> |) is present */
112 if (pipe_count > 0 && pipe_pos[0] == 2 && str_cmp(cmd[0], "from") == 0) {
113 /* Ignore the first three tokens (from, file, pipe) and set from */
114 redir_from = cmd[1];
115 actual_cmd = cmd + 3;
116 processed_pipes++;
117 }
118
119 /* Check if the second part (| to <file>) is present */
120 if ((pipe_count - processed_pipes) > 0 &&
121 pipe_pos[processed_pipes] == cmd_length - 3 &&
122 str_cmp(cmd[cmd_length-2], "to") == 0) {
123 /* Ignore the last three tokens (pipe, to, file) and set to */
124 redir_to = cmd[cmd_length-1];
125 cmd[cmd_length-3] = NULL;
126 cmd_length -= 3;
127 processed_pipes++;
128 }
129
130 if (processed_pipes != pipe_count) {
131 print_pipe_usage();
132 rc = ENOTSUP;
133 goto finit;
134 }
135
136 if (actual_cmd[0] == NULL) {
137 print_pipe_usage();
138 rc = ENOTSUP;
139 goto finit;
140 }
141
142 iostate_t new_iostate = {
143 .stdin = stdin,
144 .stdout = stdout,
145 .stderr = stderr
146 };
147
148 FILE *from = NULL;
149 FILE *to = NULL;
150
151 if (redir_from) {
152 from = fopen(redir_from, "r");
153 if (from == NULL) {
154 printf("Cannot open file %s\n", redir_from);
155 rc = errno;
156 goto finit_with_files;
157 }
158 new_iostate.stdin = from;
159 }
160
161
162 if (redir_to) {
163 to = fopen(redir_to, "w");
164 if (to == NULL) {
165 printf("Cannot open file %s\n", redir_to);
166 rc = errno;
167 goto finit_with_files;
168 }
169 new_iostate.stdout = to;
170 }
171
172 rc = run_command(cmd, usr, &new_iostate);
173
174finit_with_files:
175 if (from != NULL) {
176 fclose(from);
177 }
178 if (to != NULL) {
179 fclose(to);
180 }
181
182finit:
183 if (NULL != usr->line) {
184 free(usr->line);
185 usr->line = (char *) NULL;
186 }
187 tok_fini(&tok);
188
189 return rc;
190}
191
192void print_pipe_usage()
193{
194 printf("Invalid syntax!\n");
195 printf("Usage of redirection (pipes in the future):\n");
196 printf("from filename | command ...\n");
197 printf("from filename | command ... | to filename\n");
198 printf("command ... | to filename\n");
199
200}
201
202int run_command(char **cmd, cliuser_t *usr, iostate_t *new_iostate)
203{
204 int id = 0;
205
206 /* We have rubbish */
207 if (NULL == cmd[0]) {
208 return CL_ENOENT;
209 }
210
211 /* Is it a builtin command ? */
212 if ((id = (is_builtin(cmd[0]))) > -1) {
213 return run_builtin(id, cmd, usr, new_iostate);
214 }
215
216 /* Is it a module ? */
217 if ((id = (is_module(cmd[0]))) > -1) {
218 return run_module(id, cmd, new_iostate);
219 }
220
221 /* See what try_exec thinks of it */
222 return try_exec(cmd[0], cmd, new_iostate);
223}
224
225void get_input(cliuser_t *usr)
226{
227 char *str;
228 int rc;
229
230 console_flush(tinput->console);
231 console_set_style(tinput->console, STYLE_EMPHASIS);
232 printf("%s", usr->prompt);
233 console_flush(tinput->console);
234 console_set_style(tinput->console, STYLE_NORMAL);
235
236 rc = tinput_read(tinput, &str);
237 if (rc == ENOENT) {
238 /* User requested exit */
239 cli_quit = 1;
240 putchar('\n');
241 return;
242 }
243
244 if (rc != EOK) {
245 /* Error in communication with console */
246 return;
247 }
248
249 /* Check for empty input. */
250 if (str_cmp(str, "") == 0) {
251 free(str);
252 return;
253 }
254
255 usr->line = str;
256 return;
257}
258
259int input_init(void)
260{
261 tinput = tinput_new();
262 if (tinput == NULL) {
263 printf("Failed to initialize input.\n");
264 return 1;
265 }
266
267 return 0;
268}
Note: See TracBrowser for help on using the repository browser.