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