xref: /minix/crypto/external/bsd/heimdal/dist/lib/sl/sl.c (revision 0a6a1f1d)
1 /*	$NetBSD: sl.c,v 1.1.1.2 2014/04/24 12:45:53 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 
38 #include "sl_locl.h"
39 #include <setjmp.h>
40 
41 static void
mandoc_template(SL_cmd * cmds,const char * extra_string)42 mandoc_template(SL_cmd *cmds,
43 		const char *extra_string)
44 {
45     SL_cmd *c, *prev;
46     char timestr[64], cmd[64];
47     const char *p;
48     time_t t;
49 
50     printf(".\\\" Things to fix:\n");
51     printf(".\\\"   * correct section, and operating system\n");
52     printf(".\\\"   * remove Op from mandatory flags\n");
53     printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
54     printf(".\\\"\n");
55     t = time(NULL);
56     strftime(timestr, sizeof(timestr), "%b %d, %Y", localtime(&t));
57     printf(".Dd %s\n", timestr);
58     p = strrchr(getprogname(), '/');
59     if(p) p++; else p = getprogname();
60     strncpy(cmd, p, sizeof(cmd));
61     cmd[sizeof(cmd)-1] = '\0';
62     strupr(cmd);
63 
64     printf(".Dt %s SECTION\n", cmd);
65     printf(".Os OPERATING_SYSTEM\n");
66     printf(".Sh NAME\n");
67     printf(".Nm %s\n", p);
68     printf(".Nd\n");
69     printf("in search of a description\n");
70     printf(".Sh SYNOPSIS\n");
71     printf(".Nm\n");
72     for(c = cmds; c->name; ++c) {
73 /*	if (c->func == NULL)
74 	    continue; */
75 	printf(".Op Fl %s", c->name);
76 	printf("\n");
77 
78     }
79     if (extra_string && *extra_string)
80 	printf (".Ar %s\n", extra_string);
81     printf(".Sh DESCRIPTION\n");
82     printf("Supported options:\n");
83     printf(".Bl -tag -width Ds\n");
84     prev = NULL;
85     for(c = cmds; c->name; ++c) {
86 	if (c->func) {
87 	    if (prev)
88 		printf ("\n%s\n", prev->usage);
89 
90 	    printf (".It Fl %s", c->name);
91 	    prev = c;
92 	} else
93 	    printf (", %s\n", c->name);
94     }
95     if (prev)
96 	printf ("\n%s\n", prev->usage);
97 
98     printf(".El\n");
99     printf(".\\\".Sh ENVIRONMENT\n");
100     printf(".\\\".Sh FILES\n");
101     printf(".\\\".Sh EXAMPLES\n");
102     printf(".\\\".Sh DIAGNOSTICS\n");
103     printf(".\\\".Sh SEE ALSO\n");
104     printf(".\\\".Sh STANDARDS\n");
105     printf(".\\\".Sh HISTORY\n");
106     printf(".\\\".Sh AUTHORS\n");
107     printf(".\\\".Sh BUGS\n");
108 }
109 
110 SL_cmd *
sl_match(SL_cmd * cmds,char * cmd,int exactp)111 sl_match (SL_cmd *cmds, char *cmd, int exactp)
112 {
113     SL_cmd *c, *current = NULL, *partial_cmd = NULL;
114     int partial_match = 0;
115 
116     for (c = cmds; c->name; ++c) {
117 	if (c->func)
118 	    current = c;
119 	if (strcmp (cmd, c->name) == 0)
120 	    return current;
121 	else if (strncmp (cmd, c->name, strlen(cmd)) == 0 &&
122 		 partial_cmd != current) {
123 	    ++partial_match;
124 	    partial_cmd = current;
125 	}
126     }
127     if (partial_match == 1 && !exactp)
128 	return partial_cmd;
129     else
130 	return NULL;
131 }
132 
133 void
sl_help(SL_cmd * cmds,int argc,char ** argv)134 sl_help (SL_cmd *cmds, int argc, char **argv)
135 {
136     SL_cmd *c, *prev_c;
137 
138     if (getenv("SLMANDOC")) {
139 	mandoc_template(cmds, NULL);
140 	return;
141     }
142 
143     if (argc == 1) {
144 	prev_c = NULL;
145 	for (c = cmds; c->name; ++c) {
146 	    if (c->func) {
147 		if(prev_c)
148 		    printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "",
149 			    prev_c->usage ? "\n" : "");
150 		prev_c = c;
151 		printf ("%s", c->name);
152 	    } else
153 		printf (", %s", c->name);
154 	}
155 	if(prev_c)
156 	    printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "",
157 		    prev_c->usage ? "\n" : "");
158     } else {
159 	c = sl_match (cmds, argv[1], 0);
160 	if (c == NULL)
161 	    printf ("No such command: %s. "
162 		    "Try \"help\" for a list of all commands\n",
163 		    argv[1]);
164 	else {
165 	    printf ("%s\t%s\n", c->name, c->usage);
166 	    if(c->help && *c->help)
167 		printf ("%s\n", c->help);
168 	    if((++c)->name && c->func == NULL) {
169 		printf ("Synonyms:");
170 		while (c->name && c->func == NULL)
171 		    printf ("\t%s", (c++)->name);
172 		printf ("\n");
173 	    }
174 	}
175     }
176 }
177 
178 #ifdef HAVE_READLINE
179 
180 char *readline(char *prompt);
181 void add_history(char *p);
182 
183 #else
184 
185 static char *
readline(char * prompt)186 readline(char *prompt)
187 {
188     char buf[BUFSIZ];
189     printf ("%s", prompt);
190     fflush (stdout);
191     if(fgets(buf, sizeof(buf), stdin) == NULL)
192 	return NULL;
193     buf[strcspn(buf, "\r\n")] = '\0';
194     return strdup(buf);
195 }
196 
197 static void
add_history(char * p)198 add_history(char *p)
199 {
200 }
201 
202 #endif
203 
204 int
sl_command(SL_cmd * cmds,int argc,char ** argv)205 sl_command(SL_cmd *cmds, int argc, char **argv)
206 {
207     SL_cmd *c;
208     c = sl_match (cmds, argv[0], 0);
209     if (c == NULL)
210 	return -1;
211     return (*c->func)(argc, argv);
212 }
213 
214 struct sl_data {
215     int max_count;
216     char **ptr;
217 };
218 
219 int
sl_make_argv(char * line,int * ret_argc,char *** ret_argv)220 sl_make_argv(char *line, int *ret_argc, char ***ret_argv)
221 {
222     char *p, *begining;
223     int argc, nargv;
224     char **argv;
225     int quote = 0;
226 
227     nargv = 10;
228     argv = malloc(nargv * sizeof(*argv));
229     if(argv == NULL)
230 	return ENOMEM;
231     argc = 0;
232 
233     p = line;
234 
235     while(isspace((unsigned char)*p))
236 	p++;
237     begining = p;
238 
239     while (1) {
240 	if (*p == '\0') {
241 	    ;
242 	} else if (*p == '"') {
243 	    quote = !quote;
244 	    memmove(&p[0], &p[1], strlen(&p[1]) + 1);
245 	    continue;
246 	} else if (*p == '\\') {
247 	    if (p[1] == '\0')
248 		goto failed;
249 	    memmove(&p[0], &p[1], strlen(&p[1]) + 1);
250 	    p += 2;
251 	    continue;
252 	} else if (quote || !isspace((unsigned char)*p)) {
253 	    p++;
254 	    continue;
255 	} else
256 	    *p++ = '\0';
257 	if (quote)
258 	    goto failed;
259 	if(argc == nargv - 1) {
260 	    char **tmp;
261 	    nargv *= 2;
262 	    tmp = realloc (argv, nargv * sizeof(*argv));
263 	    if (tmp == NULL) {
264 		free(argv);
265 		return ENOMEM;
266 	    }
267 	    argv = tmp;
268 	}
269 	argv[argc++] = begining;
270 	while(isspace((unsigned char)*p))
271 	    p++;
272 	if (*p == '\0')
273 	    break;
274 	begining = p;
275     }
276     argv[argc] = NULL;
277     *ret_argc = argc;
278     *ret_argv = argv;
279     return 0;
280 failed:
281     free(argv);
282     return ERANGE;
283 }
284 
285 static jmp_buf sl_jmp;
286 
sl_sigint(int sig)287 static void sl_sigint(int sig)
288 {
289     longjmp(sl_jmp, 1);
290 }
291 
sl_readline(const char * prompt)292 static char *sl_readline(const char *prompt)
293 {
294     char *s;
295     void (*old)(int);
296     old = signal(SIGINT, sl_sigint);
297     if(setjmp(sl_jmp))
298 	printf("\n");
299     s = readline(rk_UNCONST(prompt));
300     signal(SIGINT, old);
301     return s;
302 }
303 
304 /* return values:
305  * 0 on success,
306  * -1 on fatal error,
307  * -2 if EOF, or
308  * return value of command */
309 int
sl_command_loop(SL_cmd * cmds,const char * prompt,void ** data)310 sl_command_loop(SL_cmd *cmds, const char *prompt, void **data)
311 {
312     int ret = 0;
313     char *buf;
314     int argc;
315     char **argv;
316 
317     buf = sl_readline(prompt);
318     if(buf == NULL)
319 	return -2;
320 
321     if(*buf)
322 	add_history(buf);
323     ret = sl_make_argv(buf, &argc, &argv);
324     if(ret) {
325 	fprintf(stderr, "sl_loop: out of memory\n");
326 	free(buf);
327 	return -1;
328     }
329     if (argc >= 1) {
330 	ret = sl_command(cmds, argc, argv);
331 	if(ret == -1) {
332 	    printf ("Unrecognized command: %s\n", argv[0]);
333 	    ret = 0;
334 	}
335     }
336     free(buf);
337     free(argv);
338     return ret;
339 }
340 
341 int
sl_loop(SL_cmd * cmds,const char * prompt)342 sl_loop(SL_cmd *cmds, const char *prompt)
343 {
344     void *data = NULL;
345     int ret;
346     while((ret = sl_command_loop(cmds, prompt, &data)) >= 0)
347 	;
348     return ret;
349 }
350 
351 void
sl_apropos(SL_cmd * cmd,const char * topic)352 sl_apropos (SL_cmd *cmd, const char *topic)
353 {
354     for (; cmd->name != NULL; ++cmd)
355         if (cmd->usage != NULL && strstr(cmd->usage, topic) != NULL)
356 	    printf ("%-20s%s\n", cmd->name, cmd->usage);
357 }
358 
359 /*
360  * Help to be used with slc.
361  */
362 
363 void
sl_slc_help(SL_cmd * cmds,int argc,char ** argv)364 sl_slc_help (SL_cmd *cmds, int argc, char **argv)
365 {
366     if(argc == 0) {
367 	sl_help(cmds, 1, argv - 1 /* XXX */);
368     } else {
369 	SL_cmd *c = sl_match (cmds, argv[0], 0);
370  	if(c == NULL) {
371 	    fprintf (stderr, "No such command: %s. "
372 		     "Try \"help\" for a list of commands\n",
373 		     argv[0]);
374 	} else {
375 	    if(c->func) {
376 		static char help[] = "--help";
377 		char *fake[3];
378 		fake[0] = argv[0];
379 		fake[1] = help;
380 		fake[2] = NULL;
381 		(*c->func)(2, fake);
382 		fprintf(stderr, "\n");
383 	    }
384 	    if(c->help && *c->help)
385 		fprintf (stderr, "%s\n", c->help);
386 	    if((++c)->name && c->func == NULL) {
387 		int f = 0;
388 		fprintf (stderr, "Synonyms:");
389 		while (c->name && c->func == NULL) {
390 		    fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name);
391 		    f = 1;
392 		}
393 		fprintf (stderr, "\n");
394 	    }
395 	}
396     }
397 }
398