1 /* 2 * Copyright (c) 1995 - 2001 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 #ifdef HAVE_CONFIG_H 35 #include <config.h> 36 RCSID("$Id: sl.c,v 1.29 2001/02/20 01:44:55 assar Exp $"); 37 #endif 38 39 #include "sl_locl.h" 40 #include <setjmp.h> 41 42 static size_t 43 print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c) 44 __attribute__ ((unused)); 45 46 static size_t 47 print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c) 48 { 49 if(mdoc){ 50 if(longp) 51 fprintf(stream, "= Ns"); 52 fprintf(stream, " Ar "); 53 }else 54 if (longp) 55 putc ('=', stream); 56 else 57 putc (' ', stream); 58 59 return 1; 60 } 61 62 static void 63 mandoc_template(SL_cmd *cmds, 64 const char *extra_string) 65 { 66 SL_cmd *c, *prev; 67 char timestr[64], cmd[64]; 68 const char *p; 69 time_t t; 70 71 printf(".\\\" Things to fix:\n"); 72 printf(".\\\" * correct section, and operating system\n"); 73 printf(".\\\" * remove Op from mandatory flags\n"); 74 printf(".\\\" * use better macros for arguments (like .Pa for files)\n"); 75 printf(".\\\"\n"); 76 t = time(NULL); 77 strftime(timestr, sizeof(timestr), "%b %d, %Y", localtime(&t)); 78 printf(".Dd %s\n", timestr); 79 p = strrchr(getprogname(), '/'); 80 if(p) p++; else p = getprogname(); 81 strncpy(cmd, p, sizeof(cmd)); 82 cmd[sizeof(cmd)-1] = '\0'; 83 strupr(cmd); 84 85 printf(".Dt %s SECTION\n", cmd); 86 printf(".Os OPERATING_SYSTEM\n"); 87 printf(".Sh NAME\n"); 88 printf(".Nm %s\n", p); 89 printf(".Nd\n"); 90 printf("in search of a description\n"); 91 printf(".Sh SYNOPSIS\n"); 92 printf(".Nm\n"); 93 for(c = cmds; c->name; ++c) { 94 /* if (c->func == NULL) 95 continue; */ 96 printf(".Op Fl %s", c->name); 97 /* print_sl(stdout, 1, 0, c);*/ 98 printf("\n"); 99 100 } 101 if (extra_string && *extra_string) 102 printf (".Ar %s\n", extra_string); 103 printf(".Sh DESCRIPTION\n"); 104 printf("Supported options:\n"); 105 printf(".Bl -tag -width Ds\n"); 106 prev = NULL; 107 for(c = cmds; c->name; ++c) { 108 if (c->func) { 109 if (prev) 110 printf ("\n%s\n", prev->usage); 111 112 printf (".It Fl %s", c->name); 113 prev = c; 114 } else 115 printf (", %s\n", c->name); 116 } 117 if (prev) 118 printf ("\n%s\n", prev->usage); 119 120 printf(".El\n"); 121 printf(".\\\".Sh ENVIRONMENT\n"); 122 printf(".\\\".Sh FILES\n"); 123 printf(".\\\".Sh EXAMPLES\n"); 124 printf(".\\\".Sh DIAGNOSTICS\n"); 125 printf(".\\\".Sh SEE ALSO\n"); 126 printf(".\\\".Sh STANDARDS\n"); 127 printf(".\\\".Sh HISTORY\n"); 128 printf(".\\\".Sh AUTHORS\n"); 129 printf(".\\\".Sh BUGS\n"); 130 } 131 132 static SL_cmd * 133 sl_match (SL_cmd *cmds, char *cmd, int exactp) 134 { 135 SL_cmd *c, *current = NULL, *partial_cmd = NULL; 136 int partial_match = 0; 137 138 for (c = cmds; c->name; ++c) { 139 if (c->func) 140 current = c; 141 if (strcmp (cmd, c->name) == 0) 142 return current; 143 else if (strncmp (cmd, c->name, strlen(cmd)) == 0 && 144 partial_cmd != current) { 145 ++partial_match; 146 partial_cmd = current; 147 } 148 } 149 if (partial_match == 1 && !exactp) 150 return partial_cmd; 151 else 152 return NULL; 153 } 154 155 void 156 sl_help (SL_cmd *cmds, int argc, char **argv) 157 { 158 SL_cmd *c, *prev_c; 159 160 if (getenv("SLMANDOC")) { 161 mandoc_template(cmds, NULL); 162 return; 163 } 164 165 if (argc == 1) { 166 prev_c = NULL; 167 for (c = cmds; c->name; ++c) { 168 if (c->func) { 169 if(prev_c) 170 printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "", 171 prev_c->usage ? "\n" : ""); 172 prev_c = c; 173 printf ("%s", c->name); 174 } else 175 printf (", %s", c->name); 176 } 177 if(prev_c) 178 printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "", 179 prev_c->usage ? "\n" : ""); 180 } else { 181 c = sl_match (cmds, argv[1], 0); 182 if (c == NULL) 183 printf ("No such command: %s. " 184 "Try \"help\" for a list of all commands\n", 185 argv[1]); 186 else { 187 printf ("%s\t%s\n", c->name, c->usage); 188 if(c->help && *c->help) 189 printf ("%s\n", c->help); 190 if((++c)->name && c->func == NULL) { 191 printf ("Synonyms:"); 192 while (c->name && c->func == NULL) 193 printf ("\t%s", (c++)->name); 194 printf ("\n"); 195 } 196 } 197 } 198 } 199 200 #ifdef HAVE_READLINE 201 202 char *readline(char *prompt); 203 void add_history(char *p); 204 205 #else 206 207 static char * 208 readline(char *prompt) 209 { 210 char buf[BUFSIZ]; 211 printf ("%s", prompt); 212 fflush (stdout); 213 if(fgets(buf, sizeof(buf), stdin) == NULL) 214 return NULL; 215 if (buf[strlen(buf) - 1] == '\n') 216 buf[strlen(buf) - 1] = '\0'; 217 return strdup(buf); 218 } 219 220 static void 221 add_history(char *p) 222 { 223 } 224 225 #endif 226 227 int 228 sl_command(SL_cmd *cmds, int argc, char **argv) 229 { 230 SL_cmd *c; 231 c = sl_match (cmds, argv[0], 0); 232 if (c == NULL) 233 return -1; 234 return (*c->func)(argc, argv); 235 } 236 237 struct sl_data { 238 int max_count; 239 char **ptr; 240 }; 241 242 int 243 sl_make_argv(char *line, int *ret_argc, char ***ret_argv) 244 { 245 char *foo = NULL; 246 char *p; 247 int argc, nargv; 248 char **argv; 249 250 nargv = 10; 251 argv = malloc(nargv * sizeof(*argv)); 252 if(argv == NULL) 253 return ENOMEM; 254 argc = 0; 255 256 for(p = strtok_r (line, " \t", &foo); 257 p; 258 p = strtok_r (NULL, " \t", &foo)) { 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++] = p; 270 } 271 argv[argc] = NULL; 272 *ret_argc = argc; 273 *ret_argv = argv; 274 return 0; 275 } 276 277 static jmp_buf sl_jmp; 278 279 static void sl_sigint(int sig) 280 { 281 longjmp(sl_jmp, 1); 282 } 283 284 static char *sl_readline(const char *prompt) 285 { 286 char *s; 287 void (*old)(int); 288 old = signal(SIGINT, sl_sigint); 289 if(setjmp(sl_jmp)) 290 printf("\n"); 291 s = readline((char*)prompt); 292 signal(SIGINT, old); 293 return s; 294 } 295 296 /* return values: 0 on success, -1 on fatal error, or return value of command */ 297 int 298 sl_command_loop(SL_cmd *cmds, const char *prompt, void **data) 299 { 300 int ret = 0; 301 char *buf; 302 int argc; 303 char **argv; 304 305 ret = 0; 306 buf = sl_readline(prompt); 307 if(buf == NULL) 308 return 1; 309 310 if(*buf) 311 add_history(buf); 312 ret = sl_make_argv(buf, &argc, &argv); 313 if(ret) { 314 fprintf(stderr, "sl_loop: out of memory\n"); 315 free(buf); 316 return -1; 317 } 318 if (argc >= 1) { 319 ret = sl_command(cmds, argc, argv); 320 if(ret == -1) { 321 printf ("Unrecognized command: %s\n", argv[0]); 322 ret = 0; 323 } 324 } 325 free(buf); 326 free(argv); 327 return ret; 328 } 329 330 int 331 sl_loop(SL_cmd *cmds, const char *prompt) 332 { 333 void *data = NULL; 334 int ret; 335 while((ret = sl_command_loop(cmds, prompt, &data)) == 0) 336 ; 337 return ret; 338 } 339 340 void 341 sl_apropos (SL_cmd *cmd, const char *topic) 342 { 343 for (; cmd->name != NULL; ++cmd) 344 if (cmd->usage != NULL && strstr(cmd->usage, topic) != NULL) 345 printf ("%-20s%s\n", cmd->name, cmd->usage); 346 } 347