1b528cefcSMark Murray /* 25e9cd1aeSAssar Westerlund * Copyright (c) 1995 - 2001 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #ifdef HAVE_CONFIG_H 35b528cefcSMark Murray #include <config.h> 365e9cd1aeSAssar Westerlund RCSID("$Id: sl.c,v 1.28 2001/01/26 14:58:26 joda Exp $"); 37b528cefcSMark Murray #endif 38b528cefcSMark Murray 39b528cefcSMark Murray #include "sl_locl.h" 405e9cd1aeSAssar Westerlund #include <setjmp.h> 415e9cd1aeSAssar Westerlund 425e9cd1aeSAssar Westerlund static size_t 435e9cd1aeSAssar Westerlund print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c) 445e9cd1aeSAssar Westerlund __attribute__ ((unused)); 455e9cd1aeSAssar Westerlund 465e9cd1aeSAssar Westerlund static size_t 475e9cd1aeSAssar Westerlund print_sl (FILE *stream, int mdoc, int longp, SL_cmd *c) 485e9cd1aeSAssar Westerlund { 495e9cd1aeSAssar Westerlund if(mdoc){ 505e9cd1aeSAssar Westerlund if(longp) 515e9cd1aeSAssar Westerlund fprintf(stream, "= Ns"); 525e9cd1aeSAssar Westerlund fprintf(stream, " Ar "); 535e9cd1aeSAssar Westerlund }else 545e9cd1aeSAssar Westerlund if (longp) 555e9cd1aeSAssar Westerlund putc ('=', stream); 565e9cd1aeSAssar Westerlund else 575e9cd1aeSAssar Westerlund putc (' ', stream); 585e9cd1aeSAssar Westerlund 595e9cd1aeSAssar Westerlund return 1; 605e9cd1aeSAssar Westerlund } 615e9cd1aeSAssar Westerlund 625e9cd1aeSAssar Westerlund static void 635e9cd1aeSAssar Westerlund mandoc_template(SL_cmd *cmds, 645e9cd1aeSAssar Westerlund const char *extra_string) 655e9cd1aeSAssar Westerlund { 665e9cd1aeSAssar Westerlund SL_cmd *c, *prev; 675e9cd1aeSAssar Westerlund char timestr[64], cmd[64]; 685e9cd1aeSAssar Westerlund const char *p; 695e9cd1aeSAssar Westerlund time_t t; 705e9cd1aeSAssar Westerlund 715e9cd1aeSAssar Westerlund printf(".\\\" Things to fix:\n"); 725e9cd1aeSAssar Westerlund printf(".\\\" * correct section, and operating system\n"); 735e9cd1aeSAssar Westerlund printf(".\\\" * remove Op from mandatory flags\n"); 745e9cd1aeSAssar Westerlund printf(".\\\" * use better macros for arguments (like .Pa for files)\n"); 755e9cd1aeSAssar Westerlund printf(".\\\"\n"); 765e9cd1aeSAssar Westerlund t = time(NULL); 775e9cd1aeSAssar Westerlund strftime(timestr, sizeof(timestr), "%b %d, %Y", localtime(&t)); 785e9cd1aeSAssar Westerlund printf(".Dd %s\n", timestr); 795e9cd1aeSAssar Westerlund p = strrchr(__progname, '/'); 805e9cd1aeSAssar Westerlund if(p) p++; else p = __progname; 815e9cd1aeSAssar Westerlund strncpy(cmd, p, sizeof(cmd)); 825e9cd1aeSAssar Westerlund cmd[sizeof(cmd)-1] = '\0'; 835e9cd1aeSAssar Westerlund strupr(cmd); 845e9cd1aeSAssar Westerlund 855e9cd1aeSAssar Westerlund printf(".Dt %s SECTION\n", cmd); 865e9cd1aeSAssar Westerlund printf(".Os OPERATING_SYSTEM\n"); 875e9cd1aeSAssar Westerlund printf(".Sh NAME\n"); 885e9cd1aeSAssar Westerlund printf(".Nm %s\n", p); 895e9cd1aeSAssar Westerlund printf(".Nd\n"); 905e9cd1aeSAssar Westerlund printf("in search of a description\n"); 915e9cd1aeSAssar Westerlund printf(".Sh SYNOPSIS\n"); 925e9cd1aeSAssar Westerlund printf(".Nm\n"); 935e9cd1aeSAssar Westerlund for(c = cmds; c->name; ++c) { 945e9cd1aeSAssar Westerlund /* if (c->func == NULL) 955e9cd1aeSAssar Westerlund continue; */ 965e9cd1aeSAssar Westerlund printf(".Op Fl %s", c->name); 975e9cd1aeSAssar Westerlund /* print_sl(stdout, 1, 0, c);*/ 985e9cd1aeSAssar Westerlund printf("\n"); 995e9cd1aeSAssar Westerlund 1005e9cd1aeSAssar Westerlund } 1015e9cd1aeSAssar Westerlund if (extra_string && *extra_string) 1025e9cd1aeSAssar Westerlund printf (".Ar %s\n", extra_string); 1035e9cd1aeSAssar Westerlund printf(".Sh DESCRIPTION\n"); 1045e9cd1aeSAssar Westerlund printf("Supported options:\n"); 1055e9cd1aeSAssar Westerlund printf(".Bl -tag -width Ds\n"); 1065e9cd1aeSAssar Westerlund prev = NULL; 1075e9cd1aeSAssar Westerlund for(c = cmds; c->name; ++c) { 1085e9cd1aeSAssar Westerlund if (c->func) { 1095e9cd1aeSAssar Westerlund if (prev) 1105e9cd1aeSAssar Westerlund printf ("\n%s\n", prev->usage); 1115e9cd1aeSAssar Westerlund 1125e9cd1aeSAssar Westerlund printf (".It Fl %s", c->name); 1135e9cd1aeSAssar Westerlund prev = c; 1145e9cd1aeSAssar Westerlund } else 1155e9cd1aeSAssar Westerlund printf (", %s\n", c->name); 1165e9cd1aeSAssar Westerlund } 1175e9cd1aeSAssar Westerlund if (prev) 1185e9cd1aeSAssar Westerlund printf ("\n%s\n", prev->usage); 1195e9cd1aeSAssar Westerlund 1205e9cd1aeSAssar Westerlund printf(".El\n"); 1215e9cd1aeSAssar Westerlund printf(".\\\".Sh ENVIRONMENT\n"); 1225e9cd1aeSAssar Westerlund printf(".\\\".Sh FILES\n"); 1235e9cd1aeSAssar Westerlund printf(".\\\".Sh EXAMPLES\n"); 1245e9cd1aeSAssar Westerlund printf(".\\\".Sh DIAGNOSTICS\n"); 1255e9cd1aeSAssar Westerlund printf(".\\\".Sh SEE ALSO\n"); 1265e9cd1aeSAssar Westerlund printf(".\\\".Sh STANDARDS\n"); 1275e9cd1aeSAssar Westerlund printf(".\\\".Sh HISTORY\n"); 1285e9cd1aeSAssar Westerlund printf(".\\\".Sh AUTHORS\n"); 1295e9cd1aeSAssar Westerlund printf(".\\\".Sh BUGS\n"); 1305e9cd1aeSAssar Westerlund } 131b528cefcSMark Murray 132b528cefcSMark Murray static SL_cmd * 133b528cefcSMark Murray sl_match (SL_cmd *cmds, char *cmd, int exactp) 134b528cefcSMark Murray { 135b528cefcSMark Murray SL_cmd *c, *current = NULL, *partial_cmd = NULL; 136b528cefcSMark Murray int partial_match = 0; 137b528cefcSMark Murray 138b528cefcSMark Murray for (c = cmds; c->name; ++c) { 139b528cefcSMark Murray if (c->func) 140b528cefcSMark Murray current = c; 141b528cefcSMark Murray if (strcmp (cmd, c->name) == 0) 142b528cefcSMark Murray return current; 143b528cefcSMark Murray else if (strncmp (cmd, c->name, strlen(cmd)) == 0 && 144b528cefcSMark Murray partial_cmd != current) { 145b528cefcSMark Murray ++partial_match; 146b528cefcSMark Murray partial_cmd = current; 147b528cefcSMark Murray } 148b528cefcSMark Murray } 149b528cefcSMark Murray if (partial_match == 1 && !exactp) 150b528cefcSMark Murray return partial_cmd; 151b528cefcSMark Murray else 152b528cefcSMark Murray return NULL; 153b528cefcSMark Murray } 154b528cefcSMark Murray 155b528cefcSMark Murray void 156b528cefcSMark Murray sl_help (SL_cmd *cmds, int argc, char **argv) 157b528cefcSMark Murray { 158b528cefcSMark Murray SL_cmd *c, *prev_c; 159b528cefcSMark Murray 1605e9cd1aeSAssar Westerlund if (getenv("SLMANDOC")) { 1615e9cd1aeSAssar Westerlund mandoc_template(cmds, NULL); 1625e9cd1aeSAssar Westerlund return; 1635e9cd1aeSAssar Westerlund } 1645e9cd1aeSAssar Westerlund 165b528cefcSMark Murray if (argc == 1) { 166b528cefcSMark Murray prev_c = NULL; 167b528cefcSMark Murray for (c = cmds; c->name; ++c) { 168b528cefcSMark Murray if (c->func) { 169b528cefcSMark Murray if(prev_c) 170b528cefcSMark Murray printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "", 171b528cefcSMark Murray prev_c->usage ? "\n" : ""); 172b528cefcSMark Murray prev_c = c; 173b528cefcSMark Murray printf ("%s", c->name); 174b528cefcSMark Murray } else 175b528cefcSMark Murray printf (", %s", c->name); 176b528cefcSMark Murray } 177b528cefcSMark Murray if(prev_c) 178b528cefcSMark Murray printf ("\n\t%s%s", prev_c->usage ? prev_c->usage : "", 179b528cefcSMark Murray prev_c->usage ? "\n" : ""); 180b528cefcSMark Murray } else { 181b528cefcSMark Murray c = sl_match (cmds, argv[1], 0); 182b528cefcSMark Murray if (c == NULL) 183b528cefcSMark Murray printf ("No such command: %s. " 184b528cefcSMark Murray "Try \"help\" for a list of all commands\n", 185b528cefcSMark Murray argv[1]); 186b528cefcSMark Murray else { 187b528cefcSMark Murray printf ("%s\t%s\n", c->name, c->usage); 188b528cefcSMark Murray if(c->help && *c->help) 189b528cefcSMark Murray printf ("%s\n", c->help); 190b528cefcSMark Murray if((++c)->name && c->func == NULL) { 191b528cefcSMark Murray printf ("Synonyms:"); 192b528cefcSMark Murray while (c->name && c->func == NULL) 193b528cefcSMark Murray printf ("\t%s", (c++)->name); 194b528cefcSMark Murray printf ("\n"); 195b528cefcSMark Murray } 196b528cefcSMark Murray } 197b528cefcSMark Murray } 198b528cefcSMark Murray } 199b528cefcSMark Murray 200b528cefcSMark Murray #ifdef HAVE_READLINE 201b528cefcSMark Murray 202b528cefcSMark Murray char *readline(char *prompt); 203b528cefcSMark Murray void add_history(char *p); 204b528cefcSMark Murray 205b528cefcSMark Murray #else 206b528cefcSMark Murray 207b528cefcSMark Murray static char * 208b528cefcSMark Murray readline(char *prompt) 209b528cefcSMark Murray { 210b528cefcSMark Murray char buf[BUFSIZ]; 211b528cefcSMark Murray printf ("%s", prompt); 212b528cefcSMark Murray fflush (stdout); 213b528cefcSMark Murray if(fgets(buf, sizeof(buf), stdin) == NULL) 214b528cefcSMark Murray return NULL; 215b528cefcSMark Murray if (buf[strlen(buf) - 1] == '\n') 216b528cefcSMark Murray buf[strlen(buf) - 1] = '\0'; 217b528cefcSMark Murray return strdup(buf); 218b528cefcSMark Murray } 219b528cefcSMark Murray 220b528cefcSMark Murray static void 221b528cefcSMark Murray add_history(char *p) 222b528cefcSMark Murray { 223b528cefcSMark Murray } 224b528cefcSMark Murray 225b528cefcSMark Murray #endif 226b528cefcSMark Murray 227b528cefcSMark Murray int 228b528cefcSMark Murray sl_command(SL_cmd *cmds, int argc, char **argv) 229b528cefcSMark Murray { 230b528cefcSMark Murray SL_cmd *c; 231b528cefcSMark Murray c = sl_match (cmds, argv[0], 0); 232b528cefcSMark Murray if (c == NULL) 233b528cefcSMark Murray return -1; 234b528cefcSMark Murray return (*c->func)(argc, argv); 235b528cefcSMark Murray } 236b528cefcSMark Murray 237b528cefcSMark Murray struct sl_data { 238b528cefcSMark Murray int max_count; 239b528cefcSMark Murray char **ptr; 240b528cefcSMark Murray }; 241b528cefcSMark Murray 242b528cefcSMark Murray int 243b528cefcSMark Murray sl_make_argv(char *line, int *ret_argc, char ***ret_argv) 244b528cefcSMark Murray { 245b528cefcSMark Murray char *foo = NULL; 246b528cefcSMark Murray char *p; 247b528cefcSMark Murray int argc, nargv; 248b528cefcSMark Murray char **argv; 249b528cefcSMark Murray 250b528cefcSMark Murray nargv = 10; 251b528cefcSMark Murray argv = malloc(nargv * sizeof(*argv)); 252b528cefcSMark Murray if(argv == NULL) 253b528cefcSMark Murray return ENOMEM; 254b528cefcSMark Murray argc = 0; 255b528cefcSMark Murray 256b528cefcSMark Murray for(p = strtok_r (line, " \t", &foo); 257b528cefcSMark Murray p; 258b528cefcSMark Murray p = strtok_r (NULL, " \t", &foo)) { 259b528cefcSMark Murray if(argc == nargv - 1) { 260b528cefcSMark Murray char **tmp; 261b528cefcSMark Murray nargv *= 2; 262b528cefcSMark Murray tmp = realloc (argv, nargv * sizeof(*argv)); 263b528cefcSMark Murray if (tmp == NULL) { 264b528cefcSMark Murray free(argv); 265b528cefcSMark Murray return ENOMEM; 266b528cefcSMark Murray } 267b528cefcSMark Murray argv = tmp; 268b528cefcSMark Murray } 269b528cefcSMark Murray argv[argc++] = p; 270b528cefcSMark Murray } 271b528cefcSMark Murray argv[argc] = NULL; 272b528cefcSMark Murray *ret_argc = argc; 273b528cefcSMark Murray *ret_argv = argv; 274b528cefcSMark Murray return 0; 275b528cefcSMark Murray } 276b528cefcSMark Murray 2775e9cd1aeSAssar Westerlund static jmp_buf sl_jmp; 2785e9cd1aeSAssar Westerlund 2795e9cd1aeSAssar Westerlund static void sl_sigint(int sig) 2805e9cd1aeSAssar Westerlund { 2815e9cd1aeSAssar Westerlund longjmp(sl_jmp, 1); 2825e9cd1aeSAssar Westerlund } 2835e9cd1aeSAssar Westerlund 2845e9cd1aeSAssar Westerlund static char *sl_readline(const char *prompt) 2855e9cd1aeSAssar Westerlund { 2865e9cd1aeSAssar Westerlund char *s; 2875e9cd1aeSAssar Westerlund void (*old)(int); 2885e9cd1aeSAssar Westerlund old = signal(SIGINT, sl_sigint); 2895e9cd1aeSAssar Westerlund if(setjmp(sl_jmp)) 2905e9cd1aeSAssar Westerlund printf("\n"); 2915e9cd1aeSAssar Westerlund s = readline((char*)prompt); 2925e9cd1aeSAssar Westerlund signal(SIGINT, old); 2935e9cd1aeSAssar Westerlund return s; 2945e9cd1aeSAssar Westerlund } 2955e9cd1aeSAssar Westerlund 296b528cefcSMark Murray /* return values: 0 on success, -1 on fatal error, or return value of command */ 297b528cefcSMark Murray int 2985e9cd1aeSAssar Westerlund sl_command_loop(SL_cmd *cmds, const char *prompt, void **data) 299b528cefcSMark Murray { 300b528cefcSMark Murray int ret = 0; 301b528cefcSMark Murray char *buf; 302b528cefcSMark Murray int argc; 303b528cefcSMark Murray char **argv; 304b528cefcSMark Murray 305b528cefcSMark Murray ret = 0; 3065e9cd1aeSAssar Westerlund buf = sl_readline(prompt); 307b528cefcSMark Murray if(buf == NULL) 308b528cefcSMark Murray return 1; 309b528cefcSMark Murray 310b528cefcSMark Murray if(*buf) 311b528cefcSMark Murray add_history(buf); 312b528cefcSMark Murray ret = sl_make_argv(buf, &argc, &argv); 313b528cefcSMark Murray if(ret) { 314b528cefcSMark Murray fprintf(stderr, "sl_loop: out of memory\n"); 315b528cefcSMark Murray free(buf); 316b528cefcSMark Murray return -1; 317b528cefcSMark Murray } 318b528cefcSMark Murray if (argc >= 1) { 319b528cefcSMark Murray ret = sl_command(cmds, argc, argv); 320b528cefcSMark Murray if(ret == -1) { 321b528cefcSMark Murray printf ("Unrecognized command: %s\n", argv[0]); 322b528cefcSMark Murray ret = 0; 323b528cefcSMark Murray } 324b528cefcSMark Murray } 325b528cefcSMark Murray free(buf); 326b528cefcSMark Murray free(argv); 327b528cefcSMark Murray return ret; 328b528cefcSMark Murray } 329b528cefcSMark Murray 330b528cefcSMark Murray int 3315e9cd1aeSAssar Westerlund sl_loop(SL_cmd *cmds, const char *prompt) 332b528cefcSMark Murray { 333b528cefcSMark Murray void *data = NULL; 334b528cefcSMark Murray int ret; 335b528cefcSMark Murray while((ret = sl_command_loop(cmds, prompt, &data)) == 0) 336b528cefcSMark Murray ; 337b528cefcSMark Murray return ret; 338b528cefcSMark Murray } 3395e9cd1aeSAssar Westerlund 3405e9cd1aeSAssar Westerlund void 3415e9cd1aeSAssar Westerlund sl_apropos (SL_cmd *cmd, const char *topic) 3425e9cd1aeSAssar Westerlund { 3435e9cd1aeSAssar Westerlund for (; cmd->name != NULL; ++cmd) 3445e9cd1aeSAssar Westerlund if (cmd->usage != NULL && strstr(cmd->usage, topic) != NULL) 3455e9cd1aeSAssar Westerlund printf ("%-20s%s\n", cmd->name, cmd->usage); 3465e9cd1aeSAssar Westerlund } 347