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 39static void sl_sigint(int sig) __attribute__((__noreturn__)); 40 41 42static void 43mandoc_template(SL_cmd *cmds, 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 110SL_cmd * 111sl_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 133void 134sl_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 180char *readline(char *prompt); 181void add_history(char *p); 182 183#else 184 185static char * 186readline(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 197static void 198add_history(char *p) 199{ 200} 201 202#endif 203 204int 205sl_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 214struct sl_data { 215 int max_count; 216 char **ptr; 217}; 218 219int 220sl_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; 280failed: 281 free(argv); 282 return ERANGE; 283} 284 285static jmp_buf sl_jmp; 286 287static void sl_sigint(int sig) 288{ 289 longjmp(sl_jmp, 1); 290} 291 292static 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 */ 309int 310sl_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 341int 342sl_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 351void 352sl_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 363void 364sl_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