blob: a76d15158eb2de4f1ff2a094a43db0a8a1f003bf [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2003-2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#include "platform_defs.h"
#include "command.h"
#include "input.h"
cmdinfo_t *cmdtab;
int ncmds;
static iterfunc_t iter_func;
static checkfunc_t check_func;
struct cmdline {
char *cmdline;
bool iterate;
};
static int ncmdline;
static struct cmdline *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)
{
/* always run internal library supplied commands */
if (ci->flags & CMD_FLAG_LIBRARY)
return 1;
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;
}
platform_getoptreset();
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(struct cmdline) * (ncmdline));
if (!cmdline) {
perror("realloc");
exit(1);
}
cmdline[ncmdline-1].cmdline = optarg;
cmdline[ncmdline-1].iterate = true;
}
void
add_oneshot_user_command(char *optarg)
{
ncmdline++;
cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline));
if (!cmdline) {
perror("realloc");
exit(1);
}
cmdline[ncmdline-1].cmdline = optarg;
cmdline[ncmdline-1].iterate = false;
}
/*
* Run a command, iterating as necessary. Return 0 for success, non-zero
* if an error occurred. Errors terminate loop iteration immediately.
*/
static int
iterate_command(
const cmdinfo_t *ct,
int argc,
char **argv)
{
int error = 0;
int j;
/* if there's nothing to iterate, we're done! */
if (!iter_func)
return 0;
for (j = iter_func(0); j; j = iter_func(j)) {
error = command(ct, argc, argv);
if (error)
break;
}
return error;
}
void
add_command_iterator(
iterfunc_t func)
{
iter_func = func;
}
static int
process_input(
char *input,
bool iterate)
{
char **v;
const cmdinfo_t *ct;
int c = 0;
int error = 0;
v = breakline(input, &c);
if (!c)
goto out;
ct = find_command(v[0]);
if (!ct) {
fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
goto out;
}
/* oneshot commands don't iterate */
if (!iterate || (ct->flags & CMD_FLAG_ONESHOT))
error = command(ct, c, v);
else
error = iterate_command(ct, c, v);
out:
doneline(input, v);
return error;
}
void
command_loop(void)
{
char *input;
int done = 0;
int i;
if (!cmdline) {
/* interactive mode */
while (!done) {
input = fetchline();
if (!input)
break;
done = process_input(input, false);
}
return;
}
/* command line mode */
for (i = 0; !done && i < ncmdline; i++) {
input = strdup(cmdline[i].cmdline);
if (!input) {
fprintf(stderr,
_("cannot strdup command '%s': %s\n"),
cmdline[i].cmdline, strerror(errno));
exit(1);
}
done = process_input(input, cmdline[i].iterate);
}
free(cmdline);
return;
}
void
report_io_times(
const char *verb,
struct timeval *t2,
long long offset,
long long count,
long long total,
int ops,
int compact)
{
char s1[64], s2[64], ts[64];
timestr(t2, ts, sizeof(ts), compact ? VERBOSE_FIXED_TIME : 0);
if (!compact) {
cvtstr((double)total, s1, sizeof(s1));
cvtstr(tdiv((double)total, *t2), s2, sizeof(s2));
printf(_("%s %lld/%lld bytes at offset %lld\n"),
verb, total, count, (long long)offset);
printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
s1, ops, ts, s2, tdiv((double)ops, *t2));
} else {/* bytes,ops,time,bytes/sec,ops/sec */
printf("%lld,%d,%s,%.3f,%.3f\n",
total, ops, ts,
tdiv((double)total, *t2), tdiv((double)ops, *t2));
}
}