source: mainline/uspace/app/bdsh/input.c@ 10f4b47c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 10f4b47c was 10f4b47c, checked in by Petr Koupy <petr.koupy@…>, 14 years ago

(Experimental) Added very simple support for executing batches of bdsh commands stored in a file.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2008 Tim Post
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <str.h>
33#include <io/console.h>
34#include <io/keycode.h>
35#include <io/style.h>
36#include <io/color.h>
37#include <vfs/vfs.h>
38#include <clipboard.h>
39#include <macros.h>
40#include <errno.h>
41#include <assert.h>
42#include <bool.h>
43#include <tinput.h>
44
45#include "config.h"
46#include "compl.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 if (str_cmp(actual_cmd[0], "batch") == 0 && actual_cmd[1] != NULL) {
173 FILE *batch = fopen(actual_cmd[1], "r");
174 if (batch == NULL) {
175 printf("Cannot open file %s\n", actual_cmd[1]);
176 rc = errno;
177 } else {
178 cliuser_t fusr;
179 fusr.name = usr->name;
180 fusr.cwd = usr->cwd;
181 fusr.prompt = usr->prompt;
182 fusr.line = malloc(INPUT_MAX + 1);
183 char *cur = fusr.line;
184 char *end = fusr.line + INPUT_MAX;
185 int c = fgetc(batch);
186 while (fusr.line != NULL) {
187 if (c == '\n' || c == EOF || cur == end) {
188 *cur = '\0';
189 if (cur == fusr.line) {
190 /* skip empty line */
191 rc = 0;
192 free(cur);
193 } else {
194 printf(">%s\n", fusr.line);
195 rc = process_input(&fusr);
196 /* fusr->line was freed by process_input() */
197 }
198 if (rc == 0 && c != EOF) {
199 fusr.line = malloc(INPUT_MAX + 1);
200 cur = fusr.line;
201 end = fusr.line + INPUT_MAX;
202 } else {
203 break;
204 }
205 } else {
206 *cur++ = c;
207 }
208 c = fgetc(batch);
209 }
210 fclose(batch);
211 }
212 } else {
213 rc = run_command(actual_cmd, usr, &new_iostate);
214 }
215
216finit_with_files:
217 if (from != NULL) {
218 fclose(from);
219 }
220 if (to != NULL) {
221 fclose(to);
222 }
223
224finit:
225 if (NULL != usr->line) {
226 free(usr->line);
227 usr->line = (char *) NULL;
228 }
229 tok_fini(&tok);
230
231 return rc;
232}
233
234void print_pipe_usage()
235{
236 printf("Invalid syntax!\n");
237 printf("Usage of redirection (pipes in the future):\n");
238 printf("from filename | command ...\n");
239 printf("from filename | command ... | to filename\n");
240 printf("command ... | to filename\n");
241
242}
243
244int run_command(char **cmd, cliuser_t *usr, iostate_t *new_iostate)
245{
246 int id = 0;
247
248 /* We have rubbish */
249 if (NULL == cmd[0]) {
250 return CL_ENOENT;
251 }
252
253 /* Is it a builtin command ? */
254 if ((id = (is_builtin(cmd[0]))) > -1) {
255 return run_builtin(id, cmd, usr, new_iostate);
256 }
257
258 /* Is it a module ? */
259 if ((id = (is_module(cmd[0]))) > -1) {
260 return run_module(id, cmd, new_iostate);
261 }
262
263 /* See what try_exec thinks of it */
264 return try_exec(cmd[0], cmd, new_iostate);
265}
266
267void get_input(cliuser_t *usr)
268{
269 char *str;
270 int rc;
271
272 tinput_set_prompt(tinput, usr->prompt);
273
274 rc = tinput_read(tinput, &str);
275 if (rc == ENOENT) {
276 /* User requested exit */
277 cli_quit = 1;
278 putchar('\n');
279 return;
280 }
281
282 if (rc != EOK) {
283 /* Error in communication with console */
284 return;
285 }
286
287 /* Check for empty input. */
288 if (str_cmp(str, "") == 0) {
289 free(str);
290 return;
291 }
292
293 usr->line = str;
294 return;
295}
296
297int input_init(void)
298{
299 tinput = tinput_new();
300 if (tinput == NULL) {
301 printf("Failed to initialize input.\n");
302 return 1;
303 }
304
305 tinput_set_compl_ops(tinput, &compl_ops);
306
307 return 0;
308}
Note: See TracBrowser for help on using the repository browser.