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