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