diff options
Diffstat (limited to 'cmd.c')
-rw-r--r-- | cmd.c | 565 |
1 files changed, 565 insertions, 0 deletions
@@ -0,0 +1,565 @@ +/* + * Copyright (c) 2003-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "cmd.h" + +#define _(x) x /* not gettext support yet */ + +extern int optind; + +/* from libxcmd/command.c */ + +cmdinfo_t *cmdtab; +int ncmds; + +static argsfunc_t args_func; +static checkfunc_t check_func; +static int ncmdline; +static char **cmdline; + +static int +compare(const void *a, const void *b) +{ + return strcmp(((const cmdinfo_t *)a)->name, + ((const cmdinfo_t *)b)->name); +} + +void +add_command( + const cmdinfo_t *ci) +{ + cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); + cmdtab[ncmds - 1] = *ci; + qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); +} + +static int +check_command( + const cmdinfo_t *ci) +{ + if (check_func) + return check_func(ci); + return 1; +} + +void +add_check_command( + checkfunc_t cf) +{ + check_func = cf; +} + +int +command_usage( + const cmdinfo_t *ci) +{ + printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); + return 0; +} + +int +command( + const cmdinfo_t *ct, + int argc, + char **argv) +{ + char *cmd = argv[0]; + + if (!check_command(ct)) + return 0; + + if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { + if (ct->argmax == -1) + fprintf(stderr, + _("bad argument count %d to %s, expected at least %d arguments\n"), + argc-1, cmd, ct->argmin); + else if (ct->argmin == ct->argmax) + fprintf(stderr, + _("bad argument count %d to %s, expected %d arguments\n"), + argc-1, cmd, ct->argmin); + else + fprintf(stderr, + _("bad argument count %d to %s, expected between %d and %d arguments\n"), + argc-1, cmd, ct->argmin, ct->argmax); + return 0; + } + optind = 0; + return ct->cfunc(argc, argv); +} + +const cmdinfo_t * +find_command( + const char *cmd) +{ + cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + if (strcmp(ct->name, cmd) == 0 || + (ct->altname && strcmp(ct->altname, cmd) == 0)) + return (const cmdinfo_t *)ct; + } + return NULL; +} + +void +add_user_command(char *optarg) +{ + ncmdline++; + cmdline = realloc(cmdline, sizeof(char*) * (ncmdline)); + if (!cmdline) { + perror("realloc"); + exit(1); + } + cmdline[ncmdline-1] = optarg; +} + +static int +args_command( + int index) +{ + if (args_func) + return args_func(index); + return 0; +} + +void +add_args_command( + argsfunc_t af) +{ + args_func = af; +} + +void +command_loop(void) +{ + int c, i, j = 0, done = 0; + char *input; + char **v; + const cmdinfo_t *ct; + + for (i = 0; !done && i < ncmdline; i++) { + input = strdup(cmdline[i]); + if (!input) { + fprintf(stderr, + _("cannot strdup command '%s': %s\n"), + cmdline[i], strerror(errno)); + exit(1); + } + v = breakline(input, &c); + if (c) { + ct = find_command(v[0]); + if (ct) { + if (ct->flags & CMD_FLAG_GLOBAL) + done = command(ct, c, v); + else { + j = 0; + while (!done && (j = args_command(j))) + done = command(ct, c, v); + } + } else + fprintf(stderr, _("command \"%s\" not found\n"), + v[0]); + } + doneline(input, v); + } + if (cmdline) { + free(cmdline); + return; + } + while (!done) { + if ((input = fetchline()) == NULL) + break; + v = breakline(input, &c); + if (c) { + ct = find_command(v[0]); + if (ct) + done = command(ct, c, v); + else + fprintf(stderr, _("command \"%s\" not found\n"), + v[0]); + } + doneline(input, v); + } +} + +/* from libxcmd/input.c */ + +#if defined(ENABLE_READLINE) +# include <readline/history.h> +# include <readline/readline.h> +#elif defined(ENABLE_EDITLINE) +# include <histedit.h> +#endif + +extern char *progname; + +static char * +get_prompt(void) +{ + static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; + + if (!prompt[0]) + snprintf(prompt, sizeof(prompt), "%s> ", progname); + return prompt; +} + +#if defined(ENABLE_READLINE) +char * +fetchline(void) +{ + char *line; + + line = readline(get_prompt()); + if (line && *line) + add_history(line); + return line; +} +#elif defined(ENABLE_EDITLINE) +static char *el_get_prompt(EditLine *e) { return get_prompt(); } +char * +fetchline(void) +{ + static EditLine *el; + static History *hist; + HistEvent hevent; + char *line; + int count; + + if (!el) { + hist = history_init(); + history(hist, &hevent, H_SETSIZE, 100); + el = el_init(progname, stdin, stdout, stderr); + el_source(el, NULL); + el_set(el, EL_SIGNAL, 1); + el_set(el, EL_PROMPT, el_get_prompt); + el_set(el, EL_HIST, history, (const char *)hist); + } + line = strdup(el_gets(el, &count)); + if (line) { + if (count > 0) + line[count-1] = '\0'; + if (*line) + history(hist, &hevent, H_ENTER, line); + } + return line; +} +#else +# define MAXREADLINESZ 1024 +char * +fetchline(void) +{ + char *p, *line = malloc(MAXREADLINESZ); + + if (!line) + return NULL; + printf("%s", get_prompt()); + fflush(stdout); + if (!fgets(line, MAXREADLINESZ, stdin)) { + free(line); + return NULL; + } + p = line + strlen(line); + if (p != line && p[-1] == '\n') + p[-1] = '\0'; + return line; +} +#endif + +char ** +breakline( + char *input, + int *count) +{ + int c = 0; + char *p; + char **rval = calloc(sizeof(char *), 1); + + while (rval && (p = strsep(&input, " ")) != NULL) { + if (!*p) + continue; + c++; + rval = realloc(rval, sizeof(*rval) * (c + 1)); + if (!rval) { + c = 0; + break; + } + rval[c - 1] = p; + rval[c] = NULL; + } + *count = c; + return rval; +} + +void +doneline( + char *input, + char **vec) +{ + free(input); + free(vec); +} + +#define EXABYTES(x) ((long long)(x) << 60) +#define PETABYTES(x) ((long long)(x) << 50) +#define TERABYTES(x) ((long long)(x) << 40) +#define GIGABYTES(x) ((long long)(x) << 30) +#define MEGABYTES(x) ((long long)(x) << 20) +#define KILOBYTES(x) ((long long)(x) << 10) + +long long +cvtnum( + char *s) +{ + long long i; + char *sp; + int c; + + i = strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return -1LL; + if (*sp == '\0') + return i; + + if (sp[1] != '\0') + return -1LL; + + c = tolower(*sp); + switch (c) { + default: + return i; + case 'k': + return KILOBYTES(i); + case 'm': + return MEGABYTES(i); + case 'g': + return GIGABYTES(i); + case 't': + return TERABYTES(i); + case 'p': + return PETABYTES(i); + case 'e': + return EXABYTES(i); + } + return -1LL; +} + +#define TO_EXABYTES(x) ((x) / EXABYTES(1)) +#define TO_PETABYTES(x) ((x) / PETABYTES(1)) +#define TO_TERABYTES(x) ((x) / TERABYTES(1)) +#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) +#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) +#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) + +void +cvtstr( + double value, + char *str, + size_t size) +{ + const char *fmt; + int precise; + + precise = ((double)value * 1000 == (double)(int)value * 1000); + + if (value >= EXABYTES(1)) { + fmt = precise ? "%.f EiB" : "%.3f EiB"; + snprintf(str, size, fmt, TO_EXABYTES(value)); + } else if (value >= PETABYTES(1)) { + fmt = precise ? "%.f PiB" : "%.3f PiB"; + snprintf(str, size, fmt, TO_PETABYTES(value)); + } else if (value >= TERABYTES(1)) { + fmt = precise ? "%.f TiB" : "%.3f TiB"; + snprintf(str, size, fmt, TO_TERABYTES(value)); + } else if (value >= GIGABYTES(1)) { + fmt = precise ? "%.f GiB" : "%.3f GiB"; + snprintf(str, size, fmt, TO_GIGABYTES(value)); + } else if (value >= MEGABYTES(1)) { + fmt = precise ? "%.f MiB" : "%.3f MiB"; + snprintf(str, size, fmt, TO_MEGABYTES(value)); + } else if (value >= KILOBYTES(1)) { + fmt = precise ? "%.f KiB" : "%.3f KiB"; + snprintf(str, size, fmt, TO_KILOBYTES(value)); + } else { + snprintf(str, size, "%f bytes", value); + } +} + +struct timeval +tsub(struct timeval t1, struct timeval t2) +{ + t1.tv_usec -= t2.tv_usec; + if (t1.tv_usec < 0) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + t1.tv_sec -= t2.tv_sec; + return t1; +} + +double +tdiv(double value, struct timeval tv) +{ + return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); +} + +#define HOURS(sec) ((sec) / (60 * 60)) +#define MINUTES(sec) (((sec) % (60 * 60)) / 60) +#define SECONDS(sec) ((sec) % 60) + +void +timestr( + struct timeval *tv, + char *ts, + size_t size, + int format) +{ + double usec = (double)tv->tv_usec / 1000000.0; + + if (format & TERSE_FIXED_TIME) { + if (!HOURS(tv->tv_sec)) { + snprintf(ts, size, "%u:%02u.%02u", + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) usec * 100); + return; + } + format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ + } + + if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { + snprintf(ts, size, "%u:%02u:%02u.%02u", + (unsigned int) HOURS(tv->tv_sec), + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) usec * 100); + } else { + snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000); + } +} + + +/* from libxcmd/quit.c */ + +static cmdinfo_t quit_cmd; + +/* ARGSUSED */ +static int +quit_f( + int argc, + char **argv) +{ + return 1; +} + +void +quit_init(void) +{ + quit_cmd.name = _("quit"); + quit_cmd.altname = _("q"); + quit_cmd.cfunc = quit_f; + quit_cmd.argmin = -1; + quit_cmd.argmax = -1; + quit_cmd.flags = CMD_FLAG_GLOBAL; + quit_cmd.oneline = _("exit the program"); + + add_command(&quit_cmd); +} + +/* from libxcmd/help.c */ + +static cmdinfo_t help_cmd; +static void help_onecmd(const char *cmd, const cmdinfo_t *ct); +static void help_oneline(const char *cmd, const cmdinfo_t *ct); + +static void +help_all(void) +{ + const cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) + help_oneline(ct->name, ct); + printf(_("\nUse 'help commandname' for extended help.\n")); +} + +static int +help_f( + int argc, + char **argv) +{ + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); + return 0; + } + ct = find_command(argv[1]); + if (ct == NULL) { + printf(_("command %s not found\n"), argv[1]); + return 0; + } + help_onecmd(argv[1], ct); + return 0; +} + +static void +help_onecmd( + const char *cmd, + const cmdinfo_t *ct) +{ + help_oneline(cmd, ct); + if (ct->help) + ct->help(); +} + +static void +help_oneline( + const char *cmd, + const cmdinfo_t *ct) +{ + if (cmd) + printf("%s ", cmd); + else { + printf("%s ", ct->name); + if (ct->altname) + printf("(or %s) ", ct->altname); + } + if (ct->args) + printf("%s ", ct->args); + printf("-- %s\n", ct->oneline); +} + +void +help_init(void) +{ + help_cmd.name = _("help"); + help_cmd.altname = _("?"); + help_cmd.cfunc = help_f; + help_cmd.argmin = 0; + help_cmd.argmax = 1; + help_cmd.flags = CMD_FLAG_GLOBAL; + help_cmd.args = _("[command]"); + help_cmd.oneline = _("help for one or all commands"); + + add_command(&help_cmd); +} |