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
mandoc_template(SL_cmd * cmds,const char * extra_string)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 *
sl_match(SL_cmd * cmds,char * cmd,int exactp)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
sl_help(SL_cmd * cmds,int argc,char ** argv)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 *
readline(char * prompt)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
add_history(char * p)196 add_history(char *p)
197 {
198 }
199
200 #endif
201
202 int
sl_command(SL_cmd * cmds,int argc,char ** argv)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
sl_make_argv(char * line,int * ret_argc,char *** ret_argv)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
sl_sigint(int sig)285 static void sl_sigint(int sig)
286 {
287 longjmp(sl_jmp, 1);
288 }
289
sl_readline(const char * prompt)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
sl_command_loop(SL_cmd * cmds,const char * prompt,void ** data)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
sl_loop(SL_cmd * cmds,const char * prompt)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
sl_apropos(SL_cmd * cmd,const char * topic)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
sl_slc_help(SL_cmd * cmds,int argc,char ** argv)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