1c5c4113dSnw141292 /*
2c5c4113dSnw141292  * CDDL HEADER START
3c5c4113dSnw141292  *
4c5c4113dSnw141292  * The contents of this file are subject to the terms of the
5c5c4113dSnw141292  * Common Development and Distribution License (the "License").
6c5c4113dSnw141292  * You may not use this file except in compliance with the License.
7c5c4113dSnw141292  *
8c5c4113dSnw141292  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw141292  * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw141292  * See the License for the specific language governing permissions
11c5c4113dSnw141292  * and limitations under the License.
12c5c4113dSnw141292  *
13c5c4113dSnw141292  * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw141292  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw141292  * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw141292  * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw141292  * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw141292  *
19c5c4113dSnw141292  * CDDL HEADER END
20c5c4113dSnw141292  */
21c5c4113dSnw141292 /*
224edd44c5Sjp151216  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23c5c4113dSnw141292  * Use is subject to license terms.
24c5c4113dSnw141292  */
25c5c4113dSnw141292 
26c5c4113dSnw141292 #include <stdio.h>
27c5c4113dSnw141292 #include <stdlib.h>
28c5c4113dSnw141292 #include <strings.h>
29c5c4113dSnw141292 #include <locale.h>
30c5c4113dSnw141292 #include <ctype.h>
31c5c4113dSnw141292 #ifdef WITH_LIBTECLA
32c5c4113dSnw141292 #include <libtecla.h>
33c5c4113dSnw141292 #endif
34c5c4113dSnw141292 #include "idmap_engine.h"
35c5c4113dSnw141292 
36c5c4113dSnw141292 /* The maximal line length. Longer lines may not be parsed OK. */
37c5c4113dSnw141292 #define	MAX_CMD_LINE_SZ 1023
38c5c4113dSnw141292 
39c5c4113dSnw141292 #ifdef WITH_LIBTECLA
40c5c4113dSnw141292 #define	MAX_HISTORY_LINES 1023
41c5c4113dSnw141292 static GetLine * gl_h;
42c5c4113dSnw141292 /* LINTED E_STATIC_UNUSED */
43c5c4113dSnw141292 #endif
44c5c4113dSnw141292 
45c5c4113dSnw141292 /* Array for arguments of the actuall command */
46c5c4113dSnw141292 static char ** my_argv;
47c5c4113dSnw141292 /* Allocated size for my_argv */
48c5c4113dSnw141292 static int my_argv_size = 16;
49c5c4113dSnw141292 /* Actuall length of my_argv */
50c5c4113dSnw141292 static int my_argc;
51c5c4113dSnw141292 
52c5c4113dSnw141292 /* Array for subcommands */
53c5c4113dSnw141292 static cmd_ops_t *my_comv;
54c5c4113dSnw141292 /* my_comc length */
55c5c4113dSnw141292 static int my_comc;
56c5c4113dSnw141292 
57c5c4113dSnw141292 /* Input filename specified by the -f flag */
58c5c4113dSnw141292 static char *my_filename;
59c5c4113dSnw141292 
60c5c4113dSnw141292 /*
61c5c4113dSnw141292  * Batch mode means reading file, stdin or libtecla input. Shell input is
62c5c4113dSnw141292  * a non-batch mode.
63c5c4113dSnw141292  */
64c5c4113dSnw141292 static int my_batch_mode;
65c5c4113dSnw141292 
66c5c4113dSnw141292 /* Array of all possible flags */
67c5c4113dSnw141292 static flag_t flags[FLAG_ALPHABET_SIZE];
68c5c4113dSnw141292 
69c5c4113dSnw141292 /* getopt variables */
70c5c4113dSnw141292 extern char *optarg;
71c5c4113dSnw141292 extern int optind, optopt, opterr;
72c5c4113dSnw141292 
73c5c4113dSnw141292 /* Fill the flags array: */
74c5c4113dSnw141292 static int
options_parse(int argc,char * argv[],const char * options)75c5c4113dSnw141292 options_parse(int argc, char *argv[], const char *options)
76c5c4113dSnw141292 {
77*ef150c2bSRichard Lowe 	int c;
78c5c4113dSnw141292 
79c5c4113dSnw141292 	optind = 1;
80c5c4113dSnw141292 
81c5c4113dSnw141292 	while ((c = getopt(argc, argv, options)) != EOF) {
82c5c4113dSnw141292 		switch (c) {
83c5c4113dSnw141292 		case '?':
84c5c4113dSnw141292 			return (-1);
85c5c4113dSnw141292 		case ':':
86c5c4113dSnw141292 	/* This is relevant only if options starts with ':': */
87c5c4113dSnw141292 			(void) fprintf(stderr,
88c5c4113dSnw141292 			    gettext("Option %s: missing parameter\n"),
89c5c4113dSnw141292 			    argv[optind - 1]);
90c5c4113dSnw141292 			return (-1);
91c5c4113dSnw141292 		default:
92c5c4113dSnw141292 			if (optarg == NULL)
93c5c4113dSnw141292 				flags[c] = FLAG_SET;
94c5c4113dSnw141292 			else
95c5c4113dSnw141292 				flags[c] = optarg;
96c5c4113dSnw141292 
97c5c4113dSnw141292 		}
98c5c4113dSnw141292 	}
99c5c4113dSnw141292 	return (optind);
100c5c4113dSnw141292 }
101c5c4113dSnw141292 
102c5c4113dSnw141292 /* Unset all flags */
103c5c4113dSnw141292 static void
options_clean()104c5c4113dSnw141292 options_clean()
105c5c4113dSnw141292 {
106c5c4113dSnw141292 	(void) memset(flags, 0, FLAG_ALPHABET_SIZE * sizeof (flag_t));
107c5c4113dSnw141292 }
108c5c4113dSnw141292 
109c5c4113dSnw141292 /* determine which subcommand is argv[0] and execute its handler */
110c5c4113dSnw141292 static int
run_command(int argc,char ** argv,cmd_pos_t * pos)1114edd44c5Sjp151216 run_command(int argc, char **argv, cmd_pos_t *pos)
1124edd44c5Sjp151216 {
113c5c4113dSnw141292 	int i;
114c5c4113dSnw141292 
115c5c4113dSnw141292 	if (argc == 0) {
116c5c4113dSnw141292 		if (my_batch_mode)
117c5c4113dSnw141292 			return (0);
118c5c4113dSnw141292 		return (-1);
119c5c4113dSnw141292 	}
120c5c4113dSnw141292 	for (i = 0; i < my_comc; i++) {
121c5c4113dSnw141292 		int optind;
122c5c4113dSnw141292 		int rc;
123c5c4113dSnw141292 
124c5c4113dSnw141292 		if (strcmp(my_comv[i].cmd, argv[0]) != 0)
125c5c4113dSnw141292 			continue;
126c5c4113dSnw141292 
127c5c4113dSnw141292 		/* We found it. Now execute the handler. */
128c5c4113dSnw141292 		options_clean();
129c5c4113dSnw141292 		optind = options_parse(argc, argv, my_comv[i].options);
130c5c4113dSnw141292 		if (optind < 0) {
131c5c4113dSnw141292 			return (-1);
132c5c4113dSnw141292 		}
133c5c4113dSnw141292 
1348e228215Sdm199847 		rc = my_comv[i].p_do_func(flags,
1358e228215Sdm199847 		    argc - optind,
1368e228215Sdm199847 		    argv + optind,
1378e228215Sdm199847 		    pos);
138c5c4113dSnw141292 
139c5c4113dSnw141292 		return (rc);
140c5c4113dSnw141292 	}
141c5c4113dSnw141292 
142c5c4113dSnw141292 	(void) fprintf(stderr, gettext("Unknown command %s\n"),
143c5c4113dSnw141292 	    argv[0]);
144c5c4113dSnw141292 
145c5c4113dSnw141292 	return (-1);
146c5c4113dSnw141292 
147c5c4113dSnw141292 }
148c5c4113dSnw141292 
149c5c4113dSnw141292 /*
150c5c4113dSnw141292  * Read another parameter from "from", up to a space char (unless it
151c5c4113dSnw141292  * is quoted). Duplicate it to "to". Remove quotation, if any.
152c5c4113dSnw141292  */
153c5c4113dSnw141292 static int
get_param(char ** to,const char * from)1544edd44c5Sjp151216 get_param(char **to, const char *from)
1554edd44c5Sjp151216 {
156c5c4113dSnw141292 	int to_i, from_i;
157c5c4113dSnw141292 	char c;
158c5c4113dSnw141292 	int last_slash = 0; 	/* Preceded by a slash? */
159c5c4113dSnw141292 	int in_string = 0;	/* Inside quites? */
160c5c4113dSnw141292 	int is_param = 0;
161c5c4113dSnw141292 	size_t buf_size = 20;	/* initial length of the buffer. */
162c5c4113dSnw141292 	char *buf = (char *)malloc(buf_size * sizeof (char));
163c5c4113dSnw141292 
164c5c4113dSnw141292 	from_i = 0;
165c5c4113dSnw141292 	while (isspace(from[from_i]))
166c5c4113dSnw141292 		from_i++;
167c5c4113dSnw141292 
168c5c4113dSnw141292 	for (to_i = 0; '\0' != from[from_i]; from_i++) {
169c5c4113dSnw141292 		c = from[from_i];
170c5c4113dSnw141292 
171c5c4113dSnw141292 		if (to_i >= buf_size - 1) {
172c5c4113dSnw141292 			buf_size *= 2;
173c5c4113dSnw141292 			buf = (char *)realloc(buf, buf_size * sizeof (char));
174c5c4113dSnw141292 		}
175c5c4113dSnw141292 
176c5c4113dSnw141292 		if (c == '"' && !last_slash) {
177c5c4113dSnw141292 			in_string = !in_string;
178c5c4113dSnw141292 			is_param = 1;
179c5c4113dSnw141292 			continue;
180c5c4113dSnw141292 
181c5c4113dSnw141292 		} else if (c == '\\' && !last_slash) {
182c5c4113dSnw141292 			last_slash = 1;
183c5c4113dSnw141292 			continue;
184c5c4113dSnw141292 
185c5c4113dSnw141292 		} else if (!last_slash && !in_string && isspace(c)) {
186c5c4113dSnw141292 			break;
187c5c4113dSnw141292 		}
188c5c4113dSnw141292 
189c5c4113dSnw141292 		buf[to_i++] = from[from_i];
190c5c4113dSnw141292 		last_slash = 0;
191c5c4113dSnw141292 
192c5c4113dSnw141292 	}
193c5c4113dSnw141292 
194c5c4113dSnw141292 	if (to_i == 0 && !is_param) {
195c5c4113dSnw141292 		free(buf);
196c5c4113dSnw141292 		*to = NULL;
197c5c4113dSnw141292 		return (0);
198c5c4113dSnw141292 	}
199c5c4113dSnw141292 
200c5c4113dSnw141292 	buf[to_i] = '\0';
201c5c4113dSnw141292 	*to = buf;
202c5c4113dSnw141292 
203c5c4113dSnw141292 	if (in_string)
204c5c4113dSnw141292 		return (-1);
205c5c4113dSnw141292 
206c5c4113dSnw141292 	return (from_i);
207c5c4113dSnw141292 }
208c5c4113dSnw141292 
209c5c4113dSnw141292 /*
210c5c4113dSnw141292  * Split a string to a parameter array and append it to the specified position
211c5c4113dSnw141292  * of the array
212c5c4113dSnw141292  */
213c5c4113dSnw141292 static int
line2array(const char * line)214c5c4113dSnw141292 line2array(const char *line)
215c5c4113dSnw141292 {
216c5c4113dSnw141292 	const char *cur;
217c5c4113dSnw141292 	char *param;
218c5c4113dSnw141292 	int len;
219c5c4113dSnw141292 
220c5c4113dSnw141292 	for (cur = line; len = get_param(&param, cur); cur += len) {
22161b364a9Sjp151216 		if (my_argc >= my_argv_size) {
222c5c4113dSnw141292 			my_argv_size *= 2;
223c5c4113dSnw141292 			my_argv = (char **)realloc(my_argv,
224c5c4113dSnw141292 			    my_argv_size * sizeof (char *));
225c5c4113dSnw141292 		}
226c5c4113dSnw141292 
227c5c4113dSnw141292 		my_argv[my_argc] = param;
228c5c4113dSnw141292 		++my_argc;
229c5c4113dSnw141292 
230c5c4113dSnw141292 		/* quotation not closed */
231c5c4113dSnw141292 		if (len < 0)
232c5c4113dSnw141292 			return (-1);
233c5c4113dSnw141292 
234c5c4113dSnw141292 	}
235c5c4113dSnw141292 	return (0);
236c5c4113dSnw141292 
237c5c4113dSnw141292 }
238c5c4113dSnw141292 
239c5c4113dSnw141292 /* Clean all aruments from my_argv. Don't deallocate my_argv itself. */
240c5c4113dSnw141292 static void
my_argv_clean()241c5c4113dSnw141292 my_argv_clean()
242c5c4113dSnw141292 {
243c5c4113dSnw141292 	int i;
244c5c4113dSnw141292 	for (i = 0; i < my_argc; i++) {
245c5c4113dSnw141292 		free(my_argv[i]);
246c5c4113dSnw141292 		my_argv[i] = NULL;
247c5c4113dSnw141292 	}
248c5c4113dSnw141292 	my_argc = 0;
249c5c4113dSnw141292 }
250c5c4113dSnw141292 
251c5c4113dSnw141292 
252c5c4113dSnw141292 #ifdef WITH_LIBTECLA
253c5c4113dSnw141292 /* This is libtecla tab completion. */
254c5c4113dSnw141292 static
CPL_MATCH_FN(command_complete)255c5c4113dSnw141292 CPL_MATCH_FN(command_complete)
256c5c4113dSnw141292 {
257c5c4113dSnw141292 	/*
258c5c4113dSnw141292 	 * WordCompletion *cpl; const char *line; int word_end are
259c5c4113dSnw141292 	 * passed from the CPL_MATCH_FN macro.
260c5c4113dSnw141292 	 */
261c5c4113dSnw141292 	int i;
262c5c4113dSnw141292 	char *prefix;
263c5c4113dSnw141292 	int prefix_l;
264c5c4113dSnw141292 
265c5c4113dSnw141292 	/* We go on even if quotation is not closed */
266c5c4113dSnw141292 	(void) line2array(line);
267c5c4113dSnw141292 
268c5c4113dSnw141292 
269c5c4113dSnw141292 	/* Beginning of the line: */
270c5c4113dSnw141292 	if (my_argc == 0) {
271c5c4113dSnw141292 		for (i = 0; i < my_comc; i++)
272c5c4113dSnw141292 			(void) cpl_add_completion(cpl, line, word_end,
273c5c4113dSnw141292 			    word_end, my_comv[i].cmd, "", " ");
274c5c4113dSnw141292 		goto cleanup;
275c5c4113dSnw141292 	}
276c5c4113dSnw141292 
277c5c4113dSnw141292 	/* Is there something to complete? */
278c5c4113dSnw141292 	if (isspace(line[word_end - 1]))
279c5c4113dSnw141292 		goto cleanup;
280c5c4113dSnw141292 
281c5c4113dSnw141292 	prefix = my_argv[my_argc - 1];
282c5c4113dSnw141292 	prefix_l = strlen(prefix);
283c5c4113dSnw141292 
284c5c4113dSnw141292 	/* Subcommand name: */
285c5c4113dSnw141292 	if (my_argc == 1) {
286c5c4113dSnw141292 		for (i = 0; i < my_comc; i++)
287c5c4113dSnw141292 			if (strncmp(prefix, my_comv[i].cmd, prefix_l) == 0)
288c5c4113dSnw141292 				(void) cpl_add_completion(cpl, line,
289c5c4113dSnw141292 				    word_end - prefix_l,
290c5c4113dSnw141292 				    word_end, my_comv[i].cmd + prefix_l,
291c5c4113dSnw141292 				    "", " ");
292c5c4113dSnw141292 		goto cleanup;
293c5c4113dSnw141292 	}
294c5c4113dSnw141292 
295c5c4113dSnw141292 	/* Long options: */
296c5c4113dSnw141292 	if (prefix[0] == '-' && prefix [1] == '-') {
297c5c4113dSnw141292 		char *options2 = NULL;
298c5c4113dSnw141292 		char *paren;
299c5c4113dSnw141292 		char *thesis;
300c5c4113dSnw141292 		int i;
301c5c4113dSnw141292 
302c5c4113dSnw141292 		for (i = 0; i < my_comc; i++)
303c5c4113dSnw141292 			if (0 == strcmp(my_comv[i].cmd, my_argv[0])) {
304c5c4113dSnw141292 				options2 = strdup(my_comv[i].options);
305c5c4113dSnw141292 				break;
306c5c4113dSnw141292 			}
307c5c4113dSnw141292 
308c5c4113dSnw141292 		/* No such subcommand, or not enough memory: */
309c5c4113dSnw141292 		if (options2 == NULL)
310c5c4113dSnw141292 			goto cleanup;
311c5c4113dSnw141292 
312c5c4113dSnw141292 		for (paren = strchr(options2, '(');
313c5c4113dSnw141292 		    paren && ((thesis = strchr(paren + 1, ')')) != NULL);
314c5c4113dSnw141292 		    paren = strchr(thesis + 1, '(')) {
315c5c4113dSnw141292 		/* Short option or thesis must precede, so this is safe: */
316c5c4113dSnw141292 			*(paren - 1) = '-';
317c5c4113dSnw141292 			*paren = '-';
318c5c4113dSnw141292 			*thesis = '\0';
319c5c4113dSnw141292 			if (strncmp(paren - 1, prefix, prefix_l) == 0) {
320c5c4113dSnw141292 				(void) cpl_add_completion(cpl, line,
321c5c4113dSnw141292 				    word_end - prefix_l,
322c5c4113dSnw141292 				    word_end, paren - 1 + prefix_l, "", " ");
323c5c4113dSnw141292 			}
324c5c4113dSnw141292 		}
325c5c4113dSnw141292 		free(options2);
326c5c4113dSnw141292 
327c5c4113dSnw141292 		/* "--" is a valid completion */
328c5c4113dSnw141292 		if (prefix_l == 2) {
329c5c4113dSnw141292 			(void) cpl_add_completion(cpl, line,
330c5c4113dSnw141292 			    word_end - 2,
331c5c4113dSnw141292 			    word_end, "", "", " ");
332c5c4113dSnw141292 		}
333c5c4113dSnw141292 
334c5c4113dSnw141292 	}
335c5c4113dSnw141292 
336c5c4113dSnw141292 cleanup:
337c5c4113dSnw141292 	my_argv_clean();
338c5c4113dSnw141292 	return (0);
339c5c4113dSnw141292 }
340c5c4113dSnw141292 
341c5c4113dSnw141292 /* libtecla subshell: */
342c5c4113dSnw141292 static int
interactive_interp()343c5c4113dSnw141292 interactive_interp()
344c5c4113dSnw141292 {
345c5c4113dSnw141292 	int rc = 0;
346c5c4113dSnw141292 	char *prompt;
347c5c4113dSnw141292 	const char *line;
348c5c4113dSnw141292 
349c5c4113dSnw141292 	(void) sigset(SIGINT, SIG_IGN);
350c5c4113dSnw141292 
351c5c4113dSnw141292 	gl_h = new_GetLine(MAX_CMD_LINE_SZ, MAX_HISTORY_LINES);
352c5c4113dSnw141292 
353c5c4113dSnw141292 	if (gl_h == NULL) {
354c5c4113dSnw141292 		(void) fprintf(stderr,
355c5c4113dSnw141292 		    gettext("Error reading terminal: %s.\n"),
356c5c4113dSnw141292 		    gl_error_message(gl_h, NULL, 0));
357c5c4113dSnw141292 		return (-1);
358c5c4113dSnw141292 	}
359c5c4113dSnw141292 
360c5c4113dSnw141292 	(void) gl_customize_completion(gl_h, NULL, command_complete);
361c5c4113dSnw141292 
362c5c4113dSnw141292 	for (;;) {
363c5c4113dSnw141292 new_line:
364c5c4113dSnw141292 		my_argv_clean();
365c5c4113dSnw141292 		prompt = "> ";
366c5c4113dSnw141292 continue_line:
367c5c4113dSnw141292 		line = gl_get_line(gl_h, prompt, NULL, -1);
368c5c4113dSnw141292 
369c5c4113dSnw141292 		if (line == NULL) {
370c5c4113dSnw141292 			switch (gl_return_status(gl_h)) {
371c5c4113dSnw141292 			case GLR_SIGNAL:
372c5c4113dSnw141292 				gl_abandon_line(gl_h);
373c5c4113dSnw141292 				goto new_line;
374c5c4113dSnw141292 
375c5c4113dSnw141292 			case GLR_EOF:
376c5c4113dSnw141292 				(void) line2array("exit");
377c5c4113dSnw141292 				break;
378c5c4113dSnw141292 
379c5c4113dSnw141292 			case GLR_ERROR:
380c5c4113dSnw141292 				(void) fprintf(stderr,
381c5c4113dSnw141292 				    gettext("Error reading terminal: %s.\n"),
382c5c4113dSnw141292 				    gl_error_message(gl_h, NULL, 0));
383c5c4113dSnw141292 				rc = -1;
384c5c4113dSnw141292 				goto end_of_input;
385c5c4113dSnw141292 			default:
386c5c4113dSnw141292 				(void) fprintf(stderr, "Internal error.\n");
387c5c4113dSnw141292 				exit(1);
388c5c4113dSnw141292 			}
389c5c4113dSnw141292 		} else {
390c5c4113dSnw141292 			if (line2array(line) < 0) {
391c5c4113dSnw141292 				(void) fprintf(stderr,
392c5c4113dSnw141292 				    gettext("Quotation not closed\n"));
393c5c4113dSnw141292 				goto new_line;
394c5c4113dSnw141292 			}
395c5c4113dSnw141292 			if (my_argc == 0) {
396c5c4113dSnw141292 				goto new_line;
397c5c4113dSnw141292 			}
398c5c4113dSnw141292 			if (strcmp(my_argv[my_argc-1], "\n") == 0) {
399c5c4113dSnw141292 				my_argc--;
400c5c4113dSnw141292 				free(my_argv[my_argc]);
401c5c4113dSnw141292 				(void) strcpy(prompt, "> ");
402c5c4113dSnw141292 				goto continue_line;
403c5c4113dSnw141292 			}
404c5c4113dSnw141292 		}
405c5c4113dSnw141292 
4068e228215Sdm199847 		rc = run_command(my_argc, my_argv, NULL);
407c5c4113dSnw141292 
408c5c4113dSnw141292 		if (strcmp(my_argv[0], "exit") == 0 && rc == 0) {
409c5c4113dSnw141292 			break;
410c5c4113dSnw141292 		}
411c5c4113dSnw141292 
412c5c4113dSnw141292 	}
413c5c4113dSnw141292 
414c5c4113dSnw141292 end_of_input:
415c5c4113dSnw141292 	gl_h = del_GetLine(gl_h);
416c5c4113dSnw141292 	my_argv_clean();
417c5c4113dSnw141292 	return (rc);
418c5c4113dSnw141292 }
419c5c4113dSnw141292 #endif
420c5c4113dSnw141292 
421c5c4113dSnw141292 /* Interpretation of a source file given by "name" */
422c5c4113dSnw141292 static int
source_interp(const char * name)423c5c4113dSnw141292 source_interp(const char *name)
424c5c4113dSnw141292 {
425c5c4113dSnw141292 	FILE *f;
426c5c4113dSnw141292 	int is_stdin;
427c5c4113dSnw141292 	int rc = -1;
428c5c4113dSnw141292 	char line[MAX_CMD_LINE_SZ];
4298e228215Sdm199847 	cmd_pos_t pos;
430c5c4113dSnw141292 
431c5c4113dSnw141292 	if (name == NULL || strcmp("-", name) == 0) {
432c5c4113dSnw141292 		f = stdin;
433c5c4113dSnw141292 		is_stdin = 1;
434c5c4113dSnw141292 	} else {
435c5c4113dSnw141292 		is_stdin = 0;
436c5c4113dSnw141292 		f = fopen(name, "r");
437c5c4113dSnw141292 		if (f == NULL) {
438c5c4113dSnw141292 			perror(name);
439c5c4113dSnw141292 			return (-1);
440c5c4113dSnw141292 		}
441c5c4113dSnw141292 	}
442c5c4113dSnw141292 
4438e228215Sdm199847 	pos.linenum = 0;
4448e228215Sdm199847 	pos.line = line;
4458e228215Sdm199847 
446c5c4113dSnw141292 	while (fgets(line, MAX_CMD_LINE_SZ, f)) {
4478e228215Sdm199847 		pos.linenum ++;
448c5c4113dSnw141292 
449c5c4113dSnw141292 		if (line2array(line) < 0) {
450c5c4113dSnw141292 			(void) fprintf(stderr,
451c5c4113dSnw141292 			    gettext("Quotation not closed\n"));
452c5c4113dSnw141292 			my_argv_clean();
453c5c4113dSnw141292 			continue;
454c5c4113dSnw141292 		}
455c5c4113dSnw141292 
456c5c4113dSnw141292 		/* We do not wan't "\n" as the last parameter */
457c5c4113dSnw141292 		if (my_argc != 0 && strcmp(my_argv[my_argc-1], "\n") == 0) {
458c5c4113dSnw141292 			my_argc--;
459c5c4113dSnw141292 			free(my_argv[my_argc]);
460c5c4113dSnw141292 			continue;
461c5c4113dSnw141292 		}
462c5c4113dSnw141292 
463c5c4113dSnw141292 		if (my_argc != 0 && strcmp(my_argv[0], "exit") == 0) {
464c5c4113dSnw141292 			rc = 0;
465c5c4113dSnw141292 			my_argv_clean();
466c5c4113dSnw141292 			break;
467c5c4113dSnw141292 		}
468c5c4113dSnw141292 
4698e228215Sdm199847 		rc = run_command(my_argc, my_argv, &pos);
470c5c4113dSnw141292 		my_argv_clean();
471c5c4113dSnw141292 	}
472c5c4113dSnw141292 
473c5c4113dSnw141292 	if (my_argc > 0) {
474c5c4113dSnw141292 		(void) fprintf(stderr, gettext("Line continuation missing\n"));
475c5c4113dSnw141292 		rc = 1;
476c5c4113dSnw141292 		my_argv_clean();
477c5c4113dSnw141292 	}
478c5c4113dSnw141292 
479c5c4113dSnw141292 	if (!is_stdin)
480c5c4113dSnw141292 		(void) fclose(f);
481c5c4113dSnw141292 
482c5c4113dSnw141292 	return (rc);
483c5c4113dSnw141292 }
484c5c4113dSnw141292 
485c5c4113dSnw141292 /*
486c5c4113dSnw141292  * Initialize the engine.
487c5c4113dSnw141292  * comc, comv is the array of subcommands and its length,
488c5c4113dSnw141292  * argc, argv are arguments to main to be scanned for -f filename and
489c5c4113dSnw141292  *    the length og the array,
490c5c4113dSnw141292  * is_batch_mode passes to the caller the information if the
491c5c4113dSnw141292  *    batch mode is on.
492c5c4113dSnw141292  *
493c5c4113dSnw141292  * Return values:
494c5c4113dSnw141292  * 0: ... OK
495c5c4113dSnw141292  * IDMAP_ENG_ERROR: error and message printed already
496c5c4113dSnw141292  * IDMAP_ENG_ERROR_SILENT: error and message needs to be printed
497c5c4113dSnw141292  *
498c5c4113dSnw141292  */
499c5c4113dSnw141292 
500c5c4113dSnw141292 int
engine_init(int comc,cmd_ops_t * comv,int argc,char ** argv,int * is_batch_mode)501c5c4113dSnw141292 engine_init(int comc, cmd_ops_t *comv, int argc, char **argv,
5024edd44c5Sjp151216     int *is_batch_mode)
5034edd44c5Sjp151216 {
504c5c4113dSnw141292 	int c;
505c5c4113dSnw141292 
506c5c4113dSnw141292 	my_comc = comc;
507c5c4113dSnw141292 	my_comv = comv;
508c5c4113dSnw141292 
509c5c4113dSnw141292 	my_argc = 0;
510c5c4113dSnw141292 	my_argv = (char **)calloc(my_argv_size, sizeof (char *));
511c5c4113dSnw141292 
512c5c4113dSnw141292 	if (argc < 1) {
513c5c4113dSnw141292 		my_filename = NULL;
514c5c4113dSnw141292 		if (isatty(fileno(stdin))) {
515c5c4113dSnw141292 #ifdef WITH_LIBTECLA
516c5c4113dSnw141292 			my_batch_mode = 1;
517c5c4113dSnw141292 #else
518c5c4113dSnw141292 			my_batch_mode = 0;
519c5c4113dSnw141292 			return (IDMAP_ENG_ERROR_SILENT);
520c5c4113dSnw141292 #endif
521c5c4113dSnw141292 		} else
522c5c4113dSnw141292 			my_batch_mode = 1;
523c5c4113dSnw141292 
524c5c4113dSnw141292 		goto the_end;
525c5c4113dSnw141292 	}
526c5c4113dSnw141292 
527c5c4113dSnw141292 	my_batch_mode = 0;
528c5c4113dSnw141292 
529c5c4113dSnw141292 	optind = 0;
530c5c4113dSnw141292 	while ((c = getopt(argc, argv,
531c5c4113dSnw141292 	    "f:(command-file)")) != EOF) {
532c5c4113dSnw141292 		switch (c) {
533c5c4113dSnw141292 		case '?':
534c5c4113dSnw141292 			return (IDMAP_ENG_ERROR);
535c5c4113dSnw141292 		case 'f':
536c5c4113dSnw141292 			my_batch_mode = 1;
537c5c4113dSnw141292 			my_filename = optarg;
538c5c4113dSnw141292 			break;
539c5c4113dSnw141292 		default:
540c5c4113dSnw141292 			(void) fprintf(stderr, "Internal error.\n");
541c5c4113dSnw141292 			exit(1);
542c5c4113dSnw141292 		}
543c5c4113dSnw141292 	}
544c5c4113dSnw141292 
545c5c4113dSnw141292 the_end:
546c5c4113dSnw141292 
547c5c4113dSnw141292 	if (is_batch_mode != NULL)
548c5c4113dSnw141292 		*is_batch_mode = my_batch_mode;
549c5c4113dSnw141292 	return (0);
550c5c4113dSnw141292 }
551c5c4113dSnw141292 
552c5c4113dSnw141292 /* finitialize the engine */
553c5c4113dSnw141292 int
engine_fini()5544edd44c5Sjp151216 engine_fini()
5554edd44c5Sjp151216 {
556c5c4113dSnw141292 	my_argv_clean();
557c5c4113dSnw141292 	free(my_argv);
558c5c4113dSnw141292 	return (0);
559c5c4113dSnw141292 }
560c5c4113dSnw141292 
561c5c4113dSnw141292 /*
562c5c4113dSnw141292  * Interpret the subcommands defined by the arguments, unless
563c5c4113dSnw141292  * my_batch_mode was set on in egnine_init.
564c5c4113dSnw141292  */
565c5c4113dSnw141292 int
run_engine(int argc,char ** argv)566c5c4113dSnw141292 run_engine(int argc, char **argv)
567c5c4113dSnw141292 {
568c5c4113dSnw141292 	int rc = -1;
569c5c4113dSnw141292 
570c5c4113dSnw141292 	if (my_batch_mode) {
571c5c4113dSnw141292 #ifdef WITH_LIBTECLA
572c5c4113dSnw141292 		if (isatty(fileno(stdin)))
573c5c4113dSnw141292 			rc = interactive_interp();
574c5c4113dSnw141292 		else
575c5c4113dSnw141292 #endif
576c5c4113dSnw141292 			rc = source_interp(my_filename);
577c5c4113dSnw141292 		goto cleanup;
578c5c4113dSnw141292 	}
579c5c4113dSnw141292 
5808e228215Sdm199847 	rc = run_command(argc, argv, NULL);
581c5c4113dSnw141292 
582c5c4113dSnw141292 cleanup:
583c5c4113dSnw141292 	return (rc);
584c5c4113dSnw141292 }
585