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 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 * 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 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 * 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 198 add_history(char *p) 199 { 200 } 201 202 #endif 203 204 int 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 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 287 static void sl_sigint(int sig) 288 { 289 longjmp(sl_jmp, 1); 290 } 291 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 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 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 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 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