]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/input.c
xfs_db: fix the 'source' command when passed as a -c option
[thirdparty/xfsprogs-dev.git] / db / input.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
6b803e5a 19#include "libxfs.h"
2bd0ea18 20#include <signal.h>
2bd0ea18 21#include "command.h"
2bd0ea18
NS
22#include "input.h"
23#include "output.h"
24#include "sig.h"
25#include "malloc.h"
26#include "init.h"
27
d4b9ebda 28#if defined(ENABLE_READLINE)
e246ba5f
NS
29# include <readline/history.h>
30# include <readline/readline.h>
d4b9ebda
NS
31#elif defined(ENABLE_EDITLINE)
32# include <histedit.h>
e246ba5f
NS
33#endif
34
2bd0ea18
NS
35int inputstacksize;
36FILE **inputstack;
37FILE *curinput;
38
39static void popfile(void);
40static int source_f(int argc, char **argv);
41
42static const cmdinfo_t source_cmd =
9ee7055c
AM
43 { "source", NULL, source_f, 1, 1, 0, N_("source-file"),
44 N_("get commands from source-file"), NULL };
2bd0ea18
NS
45
46/* our homegrown strtok that understands strings */
47
48static char *
49tokenize(
50 char *inp)
51{
52 static char *last_place = NULL;
53 char *start;
54 char *walk;
55 int in_string = 0;
56 int in_escape = 0;
57
58 if (inp) {
59 start = inp;
60 } else {
61 if (last_place == NULL)
62 return NULL;
63
64 /* we're done */
65 if (*last_place != '\0')
66 return NULL;
67
68 start = last_place + 1;
69 }
70 last_place = NULL;
71
72 /* eat whitespace */
73 while (*start == ' ' || *start == '\t')
74 start++;
75
76 walk = start;
77 for (;*walk != '\0'; walk++) {
78 if (in_escape) {
79 in_escape = 0;
80 continue;
81 }
82 if (*walk == '\\')
83 in_escape = 1;
84 else if (*walk == '\"')
85 in_string ^= 1;
86
87 if (!in_string && !in_escape &&
88 (*walk == ' ' || *walk == '\t')) {
89 last_place = walk;
90 *last_place = '\0';
91 break;
92 }
93 }
94 if (walk == start)
95 return NULL;
96
97 return start;
98}
99
100char **
101breakline(
102 char *input,
103 int *count)
104{
105 int c;
106 char *inp;
107 char *p;
108 char **rval;
109
110 c = 0;
111 inp = input;
112 rval = xcalloc(sizeof(char *), 1);
113 for (;;) {
114
115 p = tokenize(inp);
116
117 if (p == NULL)
118 break;
119 inp = NULL;
120 c++;
121 rval = xrealloc(rval, sizeof(*rval) * (c + 1));
122 rval[c - 1] = p;
123 rval[c] = NULL;
124 }
125 *count = c;
126 return rval;
127}
128
129void
130doneline(
131 char *input,
132 char **vec)
133{
134 xfree(input);
135 xfree(vec);
136}
137
d4b9ebda
NS
138static char *
139get_prompt(void)
140{
141 static char prompt[FILENAME_MAX + 1];
142
143 if (!prompt[0])
144 snprintf(prompt, sizeof(prompt), "%s> ", progname);
145 return prompt;
146}
147
e246ba5f
NS
148static char *
149fetchline_internal(void)
2bd0ea18
NS
150{
151 char buf[1024];
152 int iscont;
153 size_t len;
154 size_t rlen;
155 char *rval;
156
157 rval = NULL;
158 for (rlen = iscont = 0; ; ) {
c8dc4235 159 if (curinput == stdin) {
2bd0ea18
NS
160 if (iscont)
161 dbprintf("... ");
162 else
d4b9ebda 163 dbprintf(get_prompt(), progname);
2bd0ea18
NS
164 fflush(stdin);
165 }
166 if (seenint() ||
167 (!fgets(buf, sizeof(buf), curinput) &&
168 ferror(curinput) && seenint())) {
169 clearint();
170 dbprintf("^C\n");
171 clearerr(curinput);
172 if (iscont) {
173 iscont = 0;
174 rlen = 0;
175 if (rval) {
176 xfree(rval);
177 rval = NULL;
178 }
179 }
180 continue;
181 }
182 if (ferror(curinput) || feof(curinput) ||
183 (len = strlen(buf)) == 0) {
c8dc4235
DW
184 /*
185 * No more input at this inputstack level; pop
186 * our fd off and return so that a lower
187 * level fetchline can handle us. If this was
188 * an interactive session, print a newline
189 * because ^D doesn't emit one.
190 */
191 if (curinput == stdin)
2bd0ea18 192 dbprintf("\n");
c8dc4235
DW
193
194 popfile();
2bd0ea18
NS
195 iscont = 0;
196 rlen = 0;
197 if (rval) {
198 xfree(rval);
199 rval = NULL;
200 }
c8dc4235 201 return NULL;
2bd0ea18
NS
202 }
203 if (inputstacksize == 1)
204 logprintf("%s", buf);
205 rval = xrealloc(rval, rlen + len + 1);
206 if (rlen == 0)
207 rval[0] = '\0';
208 rlen += len;
209 strcat(rval, buf);
210 if (buf[len - 1] == '\n') {
211 if (len > 1 && buf[len - 2] == '\\') {
212 rval[rlen - 2] = ' ';
213 rval[rlen - 1] = '\0';
214 rlen--;
215 iscont = 1;
216 } else {
217 rval[rlen - 1] = '\0';
218 rlen--;
219 break;
220 }
221 }
222 }
223 return rval;
224}
225
e246ba5f
NS
226#ifdef ENABLE_READLINE
227char *
228fetchline(void)
2bd0ea18 229{
d4b9ebda 230 char *line;
e246ba5f
NS
231
232 if (inputstacksize == 1) {
d4b9ebda 233 line = readline(get_prompt());
c8dc4235
DW
234 if (!line)
235 dbprintf("\n");
236 else if (line && *line) {
e246ba5f 237 add_history(line);
e246ba5f 238 logprintf("%s", line);
d4b9ebda 239 }
e246ba5f
NS
240 } else {
241 line = fetchline_internal();
242 }
243 return line;
244}
d4b9ebda
NS
245#elif defined(ENABLE_EDITLINE)
246static char *el_get_prompt(EditLine *e) { return get_prompt(); }
e246ba5f
NS
247char *
248fetchline(void)
f8149110 249{
d4b9ebda
NS
250 static EditLine *el;
251 static History *hist;
252 HistEvent hevent;
f8149110 253 char *line;
d4b9ebda
NS
254 int count;
255
256 if (!el) {
257 hist = history_init();
258 history(hist, &hevent, H_SETSIZE, 100);
259 el = el_init(progname, stdin, stdout, stderr);
260 el_source(el, NULL);
261 el_set(el, EL_SIGNAL, 1);
262 el_set(el, EL_PROMPT, el_get_prompt);
263 el_set(el, EL_HIST, history, (const char *)hist);
264 }
265
266 if (inputstacksize == 1) {
267 line = xstrdup(el_gets(el, &count));
268 if (line) {
269 if (count > 0)
270 line[count-1] = '\0';
271 if (*line) {
272 history(hist, &hevent, H_ENTER, line);
273 logprintf("%s", line);
274 }
275 }
276 } else {
277 line = fetchline_internal();
278 }
279 return line;
2bd0ea18 280}
d4b9ebda
NS
281#else
282char * fetchline(void) { return fetchline_internal(); }
e246ba5f 283#endif
2bd0ea18
NS
284
285static void
286popfile(void)
287{
288 if (inputstacksize == 0) {
289 curinput = NULL;
290 return;
291 }
292 if (curinput != stdin)
293 fclose(curinput);
dfc130f3 294
2bd0ea18 295 inputstacksize--;
dfc130f3 296 if (inputstacksize) {
2bd0ea18
NS
297 inputstack =
298 xrealloc(inputstack, inputstacksize * sizeof(*inputstack));
dfc130f3
RC
299 curinput = inputstack[inputstacksize - 1];
300 } else {
301 free(inputstack);
302 curinput = NULL;
303 inputstack = NULL;
304 }
2bd0ea18
NS
305}
306
307void
308pushfile(
309 FILE *file)
310{
311 inputstack =
312 xrealloc(inputstack,
313 (inputstacksize + 1) * sizeof(*inputstack));
314 inputstacksize++;
315 curinput = inputstack[inputstacksize - 1] = file;
316}
317
318/* ARGSUSED */
319static int
320source_f(
321 int argc,
322 char **argv)
323{
324 FILE *f;
c8dc4235
DW
325 int c, done = 0;
326 char *input;
327 char **v;
2bd0ea18
NS
328
329 f = fopen(argv[1], "r");
c8dc4235 330 if (f == NULL) {
9ee7055c 331 dbprintf(_("can't open %s\n"), argv[0]);
c8dc4235
DW
332 return 0;
333 }
334
335 /* Run the sourced commands now. */
336 pushfile(f);
337 while (!done) {
338 if ((input = fetchline_internal()) == NULL)
339 break;
340 v = breakline(input, &c);
341 if (c)
342 done = command(c, v);
343 doneline(input, v);
344 }
345
2bd0ea18
NS
346 return 0;
347}
e246ba5f
NS
348
349void
350input_init(void)
351{
352 add_command(&source_cmd);
353}