xref: /freebsd/crypto/heimdal/lib/sl/sl.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*
2  * Copyright (c) 1995 - 2001 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 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id: sl.c,v 1.29 2001/02/20 01:44:55 assar Exp $");
37 #endif
38 
39 #include "sl_locl.h"
40 #include <setjmp.h>
41 
42 static size_t
43 print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c)
44     __attribute__ ((unused));
45 
46 static size_t
47 print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c)
48 {
49     if(mdoc){
50 	if(longp)
51 	    fprintf(stream, "= Ns");
52 	fprintf(stream, " Ar ");
53     }else
54 	if (longp)
55 	    putc ('=', stream);
56 	else
57 	    putc (' ', stream);
58 
59     return 1;
60 }
61 
62 static void
63 mandoc_template(SL_cmd *cmds,
64 		const char *extra_string)
65 {
66     SL_cmd *c, *prev;
67     char timestr[64], cmd[64];
68     const char *p;
69     time_t t;
70 
71     printf(".\\\" Things to fix:\n");
72     printf(".\\\"   * correct section, and operating system\n");
73     printf(".\\\"   * remove Op from mandatory flags\n");
74     printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
75     printf(".\\\"\n");
76     t = time(NULL);
77     strftime(timestr, sizeof(timestr), "%b %d, %Y", localtime(&t));
78     printf(".Dd %s\n", timestr);
79     p = strrchr(getprogname(), '/');
80     if(p) p++; else p = getprogname();
81     strncpy(cmd, p, sizeof(cmd));
82     cmd[sizeof(cmd)-1] = '\0';
83     strupr(cmd);
84 
85     printf(".Dt %s SECTION\n", cmd);
86     printf(".Os OPERATING_SYSTEM\n");
87     printf(".Sh NAME\n");
88     printf(".Nm %s\n", p);
89     printf(".Nd\n");
90     printf("in search of a description\n");
91     printf(".Sh SYNOPSIS\n");
92     printf(".Nm\n");
93     for(c = cmds; c->name; ++c) {
94 /*	if (c->func == NULL)
95 	    continue; */
96 	printf(".Op Fl %s", c->name);
97 /*	print_sl(stdout, 1, 0, c);*/
98 	printf("\n");
99 
100     }
101     if (extra_string && *extra_string)
102 	printf (".Ar %s\n", extra_string);
103     printf(".Sh DESCRIPTION\n");
104     printf("Supported options:\n");
105     printf(".Bl -tag -width Ds\n");
106     prev = NULL;
107     for(c = cmds; c->name; ++c) {
108 	if (c->func) {
109 	    if (prev)
110 		printf ("\n%s\n", prev->usage);
111 
112 	    printf (".It Fl %s", c->name);
113 	    prev = c;
114 	} else
115 	    printf (", %s\n", c->name);
116     }
117     if (prev)
118 	printf ("\n%s\n", prev->usage);
119 
120     printf(".El\n");
121     printf(".\\\".Sh ENVIRONMENT\n");
122     printf(".\\\".Sh FILES\n");
123     printf(".\\\".Sh EXAMPLES\n");
124     printf(".\\\".Sh DIAGNOSTICS\n");
125     printf(".\\\".Sh SEE ALSO\n");
126     printf(".\\\".Sh STANDARDS\n");
127     printf(".\\\".Sh HISTORY\n");
128     printf(".\\\".Sh AUTHORS\n");
129     printf(".\\\".Sh BUGS\n");
130 }
131 
132 static SL_cmd *
133 sl_match (SL_cmd *cmds, char *cmd, int exactp)
134 {
135     SL_cmd *c, *current = NULL, *partial_cmd = NULL;
136     int partial_match = 0;
137 
138     for (c = cmds; c->name; ++c) {
139 	if (c->func)
140 	    current = c;
141 	if (strcmp (cmd, c->name) == 0)
142 	    return current;
143 	else if (strncmp (cmd, c->name, strlen(cmd)) == 0 &&
144 		 partial_cmd != current) {
145 	    ++partial_match;
146 	    partial_cmd = current;
147 	}
148     }
149     if (partial_match == 1 && !exactp)
150 	return partial_cmd;
151     else
152 	return NULL;
153 }
154 
155 void
156 sl_help (SL_cmd *cmds, int argc, char **argv)
157 {
158     SL_cmd *c, *prev_c;
159 
160     if (getenv("SLMANDOC")) {
161 	mandoc_template(cmds, NULL);
162 	return;
163     }
164 
165     if (argc == 1) {
166 	prev_c = NULL;
167 	for (c = cmds; c->name; ++c) {
168 	    if (c->func) {
169 		if(prev_c)
170 		    printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "",
171 			    prev_c->usage ? "\n" : "");
172 		prev_c = c;
173 		printf ("%s", c->name);
174 	    } else
175 		printf (", %s", c->name);
176 	}
177 	if(prev_c)
178 	    printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "",
179 		    prev_c->usage ? "\n" : "");
180     } else {
181 	c = sl_match (cmds, argv[1], 0);
182 	if (c == NULL)
183 	    printf ("No such command: %s. "
184 		    "Try \"help\" for a list of all commands\n",
185 		    argv[1]);
186 	else {
187 	    printf ("%s\t%s\n", c->name, c->usage);
188 	    if(c->help && *c->help)
189 		printf ("%s\n", c->help);
190 	    if((++c)->name && c->func == NULL) {
191 		printf ("Synonyms:");
192 		while (c->name && c->func == NULL)
193 		    printf ("\t%s", (c++)->name);
194 		printf ("\n");
195 	    }
196 	}
197     }
198 }
199 
200 #ifdef HAVE_READLINE
201 
202 char *readline(char *prompt);
203 void add_history(char *p);
204 
205 #else
206 
207 static char *
208 readline(char *prompt)
209 {
210     char buf[BUFSIZ];
211     printf ("%s", prompt);
212     fflush (stdout);
213     if(fgets(buf, sizeof(buf), stdin) == NULL)
214 	return NULL;
215     if (buf[strlen(buf) - 1] == '\n')
216 	buf[strlen(buf) - 1] = '\0';
217     return strdup(buf);
218 }
219 
220 static void
221 add_history(char *p)
222 {
223 }
224 
225 #endif
226 
227 int
228 sl_command(SL_cmd *cmds, int argc, char **argv)
229 {
230     SL_cmd *c;
231     c = sl_match (cmds, argv[0], 0);
232     if (c == NULL)
233 	return -1;
234     return (*c->func)(argc, argv);
235 }
236 
237 struct sl_data {
238     int max_count;
239     char **ptr;
240 };
241 
242 int
243 sl_make_argv(char *line, int *ret_argc, char ***ret_argv)
244 {
245     char *foo = NULL;
246     char *p;
247     int argc, nargv;
248     char **argv;
249 
250     nargv = 10;
251     argv = malloc(nargv * sizeof(*argv));
252     if(argv == NULL)
253 	return ENOMEM;
254     argc = 0;
255 
256     for(p = strtok_r (line, " \t", &foo);
257 	p;
258 	p = strtok_r (NULL, " \t", &foo)) {
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++] = p;
270     }
271     argv[argc] = NULL;
272     *ret_argc = argc;
273     *ret_argv = argv;
274     return 0;
275 }
276 
277 static jmp_buf sl_jmp;
278 
279 static void sl_sigint(int sig)
280 {
281     longjmp(sl_jmp, 1);
282 }
283 
284 static char *sl_readline(const char *prompt)
285 {
286     char *s;
287     void (*old)(int);
288     old = signal(SIGINT, sl_sigint);
289     if(setjmp(sl_jmp))
290 	printf("\n");
291     s = readline((char*)prompt);
292     signal(SIGINT, old);
293     return s;
294 }
295 
296 /* return values: 0 on success, -1 on fatal error, or return value of command */
297 int
298 sl_command_loop(SL_cmd *cmds, const char *prompt, void **data)
299 {
300     int ret = 0;
301     char *buf;
302     int argc;
303     char **argv;
304 
305     ret = 0;
306     buf = sl_readline(prompt);
307     if(buf == NULL)
308 	return 1;
309 
310     if(*buf)
311 	add_history(buf);
312     ret = sl_make_argv(buf, &argc, &argv);
313     if(ret) {
314 	fprintf(stderr, "sl_loop: out of memory\n");
315 	free(buf);
316 	return -1;
317     }
318     if (argc >= 1) {
319 	ret = sl_command(cmds, argc, argv);
320 	if(ret == -1) {
321 	    printf ("Unrecognized command: %s\n", argv[0]);
322 	    ret = 0;
323 	}
324     }
325     free(buf);
326     free(argv);
327     return ret;
328 }
329 
330 int
331 sl_loop(SL_cmd *cmds, const char *prompt)
332 {
333     void *data = NULL;
334     int ret;
335     while((ret = sl_command_loop(cmds, prompt, &data)) == 0)
336 	;
337     return ret;
338 }
339 
340 void
341 sl_apropos (SL_cmd *cmd, const char *topic)
342 {
343     for (; cmd->name != NULL; ++cmd)
344         if (cmd->usage != NULL && strstr(cmd->usage, topic) != NULL)
345 	    printf ("%-20s%s\n", cmd->name, cmd->usage);
346 }
347