File:  [Qemu by Fabrice Bellard] / qemu / cmd.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:35:11 2018 UTC (2 years, 4 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, HEAD
qemu 0.12.0

    1: /*
    2:  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
    3:  * All Rights Reserved.
    4:  *
    5:  * This program is free software; you can redistribute it and/or
    6:  * modify it under the terms of the GNU General Public License as
    7:  * published by the Free Software Foundation.
    8:  *
    9:  * This program is distributed in the hope that it would be useful,
   10:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12:  * GNU General Public License for more details.
   13:  *
   14:  * You should have received a copy of the GNU General Public License
   15:  * along with this program; if not, see <http://www.gnu.org/licenses/>.
   16:  */
   17: 
   18: #include <stdio.h>
   19: #include <stdlib.h>
   20: #include <string.h>
   21: #include <ctype.h>
   22: #include <errno.h>
   23: #include <sys/time.h>
   24: #include <getopt.h>
   25: 
   26: #include "cmd.h"
   27: 
   28: #define _(x)	x	/* not gettext support yet */
   29: 
   30: /* from libxcmd/command.c */
   31: 
   32: cmdinfo_t	*cmdtab;
   33: int		ncmds;
   34: 
   35: static argsfunc_t	args_func;
   36: static checkfunc_t	check_func;
   37: static int		ncmdline;
   38: static char		**cmdline;
   39: 
   40: static int
   41: compare(const void *a, const void *b)
   42: {
   43: 	return strcmp(((const cmdinfo_t *)a)->name,
   44: 		      ((const cmdinfo_t *)b)->name);
   45: }
   46: 
   47: void
   48: add_command(
   49: 	const cmdinfo_t	*ci)
   50: {
   51: 	cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
   52: 	cmdtab[ncmds - 1] = *ci;
   53: 	qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
   54: }
   55: 
   56: static int
   57: check_command(
   58: 	const cmdinfo_t	*ci)
   59: {
   60: 	if (check_func)
   61: 		return check_func(ci);
   62: 	return 1;
   63: }
   64: 
   65: void
   66: add_check_command(
   67: 	checkfunc_t	cf)
   68: {
   69: 	check_func = cf;
   70: }
   71: 
   72: int
   73: command_usage(
   74: 	const cmdinfo_t *ci)
   75: {
   76: 	printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
   77: 	return 0;
   78: }
   79: 
   80: int
   81: command(
   82: 	const cmdinfo_t	*ct,
   83: 	int		argc,
   84: 	char		**argv)
   85: {
   86: 	char		*cmd = argv[0];
   87: 
   88: 	if (!check_command(ct))
   89: 		return 0;
   90: 
   91: 	if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
   92: 		if (ct->argmax == -1)
   93: 			fprintf(stderr,
   94: 	_("bad argument count %d to %s, expected at least %d arguments\n"),
   95: 				argc-1, cmd, ct->argmin);
   96: 		else if (ct->argmin == ct->argmax)
   97: 			fprintf(stderr,
   98: 	_("bad argument count %d to %s, expected %d arguments\n"),
   99: 				argc-1, cmd, ct->argmin);
  100: 		else
  101: 			fprintf(stderr,
  102: 	_("bad argument count %d to %s, expected between %d and %d arguments\n"),
  103: 			argc-1, cmd, ct->argmin, ct->argmax);
  104: 		return 0;
  105: 	}
  106: 	optind = 0;
  107: 	return ct->cfunc(argc, argv);
  108: }
  109: 
  110: const cmdinfo_t *
  111: find_command(
  112: 	const char	*cmd)
  113: {
  114: 	cmdinfo_t	*ct;
  115: 
  116: 	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
  117: 		if (strcmp(ct->name, cmd) == 0 ||
  118: 		    (ct->altname && strcmp(ct->altname, cmd) == 0))
  119: 			return (const cmdinfo_t *)ct;
  120: 	}
  121: 	return NULL;
  122: }
  123: 
  124: void
  125: add_user_command(char *optarg)
  126: {
  127: 	ncmdline++;
  128: 	cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
  129: 	if (!cmdline) {
  130: 		perror("realloc");
  131: 		exit(1);
  132: 	}
  133: 	cmdline[ncmdline-1] = optarg;
  134: }
  135: 
  136: static int
  137: args_command(
  138: 	int	index)
  139: {
  140: 	if (args_func)
  141: 		return args_func(index);
  142: 	return 0;
  143: }
  144: 
  145: void
  146: add_args_command(
  147: 	argsfunc_t	af)
  148: {
  149: 	args_func = af;
  150: }
  151: 
  152: void
  153: command_loop(void)
  154: {
  155: 	int		c, i, j = 0, done = 0;
  156: 	char		*input;
  157: 	char		**v;
  158: 	const cmdinfo_t	*ct;
  159: 
  160: 	for (i = 0; !done && i < ncmdline; i++) {
  161: 		input = strdup(cmdline[i]);
  162: 		if (!input) {
  163: 			fprintf(stderr,
  164: 				_("cannot strdup command '%s': %s\n"),
  165: 				cmdline[i], strerror(errno));
  166: 			exit(1);
  167: 		}
  168: 		v = breakline(input, &c);
  169: 		if (c) {
  170: 			ct = find_command(v[0]);
  171: 			if (ct) {
  172: 				if (ct->flags & CMD_FLAG_GLOBAL)
  173: 					done = command(ct, c, v);
  174: 				else {
  175: 					j = 0;
  176: 					while (!done && (j = args_command(j)))
  177: 						done = command(ct, c, v);
  178: 				}
  179: 			} else
  180: 				fprintf(stderr, _("command \"%s\" not found\n"),
  181: 					v[0]);
  182: 		}
  183: 		doneline(input, v);
  184: 	}
  185: 	if (cmdline) {
  186: 		free(cmdline);
  187: 		return;
  188: 	}
  189: 	while (!done) {
  190: 		if ((input = fetchline()) == NULL)
  191: 			break;
  192: 		v = breakline(input, &c);
  193: 		if (c) {
  194: 			ct = find_command(v[0]);
  195: 			if (ct)
  196: 				done = command(ct, c, v);
  197: 			else
  198: 				fprintf(stderr, _("command \"%s\" not found\n"),
  199: 					v[0]);
  200: 		}
  201: 		doneline(input, v);
  202: 	}
  203: }
  204: 
  205: /* from libxcmd/input.c */
  206: 
  207: #if defined(ENABLE_READLINE)
  208: # include <readline/history.h>
  209: # include <readline/readline.h>
  210: #elif defined(ENABLE_EDITLINE)
  211: # include <histedit.h>
  212: #endif
  213: 
  214: static char *
  215: get_prompt(void)
  216: {
  217: 	static char	prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
  218: 
  219: 	if (!prompt[0])
  220: 		snprintf(prompt, sizeof(prompt), "%s> ", progname);
  221: 	return prompt;
  222: }
  223: 
  224: #if defined(ENABLE_READLINE)
  225: char *
  226: fetchline(void)
  227: {
  228: 	char	*line;
  229: 
  230: 	line = readline(get_prompt());
  231: 	if (line && *line)
  232: 		add_history(line);
  233: 	return line;
  234: }
  235: #elif defined(ENABLE_EDITLINE)
  236: static char *el_get_prompt(EditLine *e) { return get_prompt(); }
  237: char *
  238: fetchline(void)
  239: {
  240: 	static EditLine	*el;
  241: 	static History	*hist;
  242: 	HistEvent	hevent;
  243: 	char		*line;
  244: 	int		count;
  245: 
  246: 	if (!el) {
  247: 		hist = history_init();
  248: 		history(hist, &hevent, H_SETSIZE, 100);
  249: 		el = el_init(progname, stdin, stdout, stderr);
  250: 		el_source(el, NULL);
  251: 		el_set(el, EL_SIGNAL, 1);
  252: 		el_set(el, EL_PROMPT, el_get_prompt);
  253: 		el_set(el, EL_HIST, history, (const char *)hist);
  254: 	}
  255: 	line = strdup(el_gets(el, &count));
  256: 	if (line) {
  257: 		if (count > 0)
  258: 			line[count-1] = '\0';
  259: 		if (*line)
  260: 			history(hist, &hevent, H_ENTER, line);
  261: 	}
  262: 	return line;
  263: }
  264: #else
  265: # define MAXREADLINESZ	1024
  266: char *
  267: fetchline(void)
  268: {
  269: 	char	*p, *line = malloc(MAXREADLINESZ);
  270: 
  271: 	if (!line)
  272: 		return NULL;
  273: 	printf("%s", get_prompt());
  274: 	fflush(stdout);
  275: 	if (!fgets(line, MAXREADLINESZ, stdin)) {
  276: 		free(line);
  277: 		return NULL;
  278: 	}
  279: 	p = line + strlen(line);
  280: 	if (p != line && p[-1] == '\n')
  281: 		p[-1] = '\0';
  282: 	return line;
  283: }
  284: #endif
  285: 
  286: static char *qemu_strsep(char **input, const char *delim)
  287: {
  288:     char *result = *input;
  289:     if (result != NULL) {
  290:         char *p = result;
  291:         for (p = result; *p != '\0'; p++) {
  292:             if (strchr(delim, *p)) {
  293:                 break;
  294:             }
  295:         }
  296:         if (*p == '\0') {
  297:             *input = NULL;
  298:         } else {
  299:             *p = '\0';
  300:             *input = p + 1;
  301:         }
  302:     }
  303:     return result;
  304: }
  305: 
  306: char **
  307: breakline(
  308: 	char	*input,
  309: 	int	*count)
  310: {
  311: 	int	c = 0;
  312: 	char	*p;
  313: 	char	**rval = calloc(sizeof(char *), 1);
  314: 
  315: 	while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
  316: 		if (!*p)
  317: 			continue;
  318: 		c++;
  319: 		rval = realloc(rval, sizeof(*rval) * (c + 1));
  320: 		if (!rval) {
  321: 			c = 0;
  322: 			break;
  323: 		}
  324: 		rval[c - 1] = p;
  325: 		rval[c] = NULL;
  326: 	}
  327: 	*count = c;
  328: 	return rval;
  329: }
  330: 
  331: void
  332: doneline(
  333: 	char	*input,
  334: 	char	**vec)
  335: {
  336: 	free(input);
  337: 	free(vec);
  338: }
  339: 
  340: #define EXABYTES(x)	((long long)(x) << 60)
  341: #define PETABYTES(x)	((long long)(x) << 50)
  342: #define TERABYTES(x)	((long long)(x) << 40)
  343: #define GIGABYTES(x)	((long long)(x) << 30)
  344: #define MEGABYTES(x)	((long long)(x) << 20)
  345: #define KILOBYTES(x)	((long long)(x) << 10)
  346: 
  347: long long
  348: cvtnum(
  349: 	char		*s)
  350: {
  351: 	long long	i;
  352: 	char		*sp;
  353: 	int		c;
  354: 
  355: 	i = strtoll(s, &sp, 0);
  356: 	if (i == 0 && sp == s)
  357: 		return -1LL;
  358: 	if (*sp == '\0')
  359: 		return i;
  360: 
  361: 	if (sp[1] != '\0')
  362: 		return -1LL;
  363: 
  364: 	c = tolower(*sp);
  365: 	switch (c) {
  366: 	default:
  367: 		return i;
  368: 	case 'k':
  369: 		return KILOBYTES(i);
  370: 	case 'm':
  371: 		return MEGABYTES(i);
  372: 	case 'g':
  373: 		return GIGABYTES(i);
  374: 	case 't':
  375: 		return TERABYTES(i);
  376: 	case 'p':
  377: 		return PETABYTES(i);
  378: 	case 'e':
  379: 		return  EXABYTES(i);
  380: 	}
  381: 	return -1LL;
  382: }
  383: 
  384: #define TO_EXABYTES(x)	((x) / EXABYTES(1))
  385: #define TO_PETABYTES(x)	((x) / PETABYTES(1))
  386: #define TO_TERABYTES(x)	((x) / TERABYTES(1))
  387: #define TO_GIGABYTES(x)	((x) / GIGABYTES(1))
  388: #define TO_MEGABYTES(x)	((x) / MEGABYTES(1))
  389: #define TO_KILOBYTES(x)	((x) / KILOBYTES(1))
  390: 
  391: void
  392: cvtstr(
  393: 	double		value,
  394: 	char		*str,
  395: 	size_t		size)
  396: {
  397: 	const char	*fmt;
  398: 	int		precise;
  399: 
  400: 	precise = ((double)value * 1000 == (double)(int)value * 1000);
  401: 
  402: 	if (value >= EXABYTES(1)) {
  403: 		fmt = precise ? "%.f EiB" : "%.3f EiB";
  404: 		snprintf(str, size, fmt, TO_EXABYTES(value));
  405: 	} else if (value >= PETABYTES(1)) {
  406: 		fmt = precise ? "%.f PiB" : "%.3f PiB";
  407: 		snprintf(str, size, fmt, TO_PETABYTES(value));
  408: 	} else if (value >= TERABYTES(1)) {
  409: 		fmt = precise ? "%.f TiB" : "%.3f TiB";
  410: 		snprintf(str, size, fmt, TO_TERABYTES(value));
  411: 	} else if (value >= GIGABYTES(1)) {
  412: 		fmt = precise ? "%.f GiB" : "%.3f GiB";
  413: 		snprintf(str, size, fmt, TO_GIGABYTES(value));
  414: 	} else if (value >= MEGABYTES(1)) {
  415: 		fmt = precise ? "%.f MiB" : "%.3f MiB";
  416: 		snprintf(str, size, fmt, TO_MEGABYTES(value));
  417: 	} else if (value >= KILOBYTES(1)) {
  418: 		fmt = precise ? "%.f KiB" : "%.3f KiB";
  419: 		snprintf(str, size, fmt, TO_KILOBYTES(value));
  420: 	} else {
  421: 		snprintf(str, size, "%f bytes", value);
  422: 	}
  423: }
  424: 
  425: struct timeval
  426: tsub(struct timeval t1, struct timeval t2)
  427: {
  428: 	t1.tv_usec -= t2.tv_usec;
  429: 	if (t1.tv_usec < 0) {
  430: 		t1.tv_usec += 1000000;
  431: 		t1.tv_sec--;
  432: 	}
  433: 	t1.tv_sec -= t2.tv_sec;
  434: 	return t1;
  435: }
  436: 
  437: double
  438: tdiv(double value, struct timeval tv)
  439: {
  440: 	return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
  441: }
  442: 
  443: #define HOURS(sec)	((sec) / (60 * 60))
  444: #define MINUTES(sec)	(((sec) % (60 * 60)) / 60)
  445: #define SECONDS(sec)	((sec) % 60)
  446: 
  447: void
  448: timestr(
  449: 	struct timeval	*tv,
  450: 	char		*ts,
  451: 	size_t		size,
  452: 	int		format)
  453: {
  454: 	double		usec = (double)tv->tv_usec / 1000000.0;
  455: 
  456: 	if (format & TERSE_FIXED_TIME) {
  457: 		if (!HOURS(tv->tv_sec)) {
  458: 			snprintf(ts, size, "%u:%02u.%02u",
  459: 				(unsigned int) MINUTES(tv->tv_sec),
  460: 				(unsigned int) SECONDS(tv->tv_sec),
  461: 				(unsigned int) usec * 100);
  462: 			return;
  463: 		}
  464: 		format |= VERBOSE_FIXED_TIME;	/* fallback if hours needed */
  465: 	}
  466: 
  467: 	if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
  468: 		snprintf(ts, size, "%u:%02u:%02u.%02u",
  469: 			(unsigned int) HOURS(tv->tv_sec),
  470: 			(unsigned int) MINUTES(tv->tv_sec),
  471: 			(unsigned int) SECONDS(tv->tv_sec),
  472: 			(unsigned int) usec * 100);
  473: 	} else {
  474: 		snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
  475: 	}
  476: }
  477: 
  478: 
  479: /* from libxcmd/quit.c */
  480: 
  481: static cmdinfo_t quit_cmd;
  482: 
  483: /* ARGSUSED */
  484: static int
  485: quit_f(
  486: 	int	argc,
  487: 	char	**argv)
  488: {
  489: 	return 1;
  490: }
  491: 
  492: void
  493: quit_init(void)
  494: {
  495: 	quit_cmd.name = _("quit");
  496: 	quit_cmd.altname = _("q");
  497: 	quit_cmd.cfunc = quit_f;
  498: 	quit_cmd.argmin = -1;
  499: 	quit_cmd.argmax = -1;
  500: 	quit_cmd.flags = CMD_FLAG_GLOBAL;
  501: 	quit_cmd.oneline = _("exit the program");
  502: 
  503: 	add_command(&quit_cmd);
  504: }
  505: 
  506: /* from libxcmd/help.c */
  507: 
  508: static cmdinfo_t help_cmd;
  509: static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
  510: static void help_oneline(const char *cmd, const cmdinfo_t *ct);
  511: 
  512: static void
  513: help_all(void)
  514: {
  515: 	const cmdinfo_t	*ct;
  516: 
  517: 	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
  518: 		help_oneline(ct->name, ct);
  519: 	printf(_("\nUse 'help commandname' for extended help.\n"));
  520: }
  521: 
  522: static int
  523: help_f(
  524: 	int		argc,
  525: 	char		**argv)
  526: {
  527: 	const cmdinfo_t	*ct;
  528: 
  529: 	if (argc == 1) {
  530: 		help_all();
  531: 		return 0;
  532: 	}
  533: 	ct = find_command(argv[1]);
  534: 	if (ct == NULL) {
  535: 		printf(_("command %s not found\n"), argv[1]);
  536: 		return 0;
  537: 	}
  538: 	help_onecmd(argv[1], ct);
  539: 	return 0;
  540: }
  541: 
  542: static void
  543: help_onecmd(
  544: 	const char	*cmd,
  545: 	const cmdinfo_t	*ct)
  546: {
  547: 	help_oneline(cmd, ct);
  548: 	if (ct->help)
  549: 		ct->help();
  550: }
  551: 
  552: static void
  553: help_oneline(
  554: 	const char	*cmd,
  555: 	const cmdinfo_t	*ct)
  556: {
  557: 	if (cmd)
  558: 		printf("%s ", cmd);
  559: 	else {
  560: 		printf("%s ", ct->name);
  561: 		if (ct->altname)
  562: 			printf("(or %s) ", ct->altname);
  563: 	}
  564: 	if (ct->args)
  565: 		printf("%s ", ct->args);
  566: 	printf("-- %s\n", ct->oneline);
  567: }
  568: 
  569: void
  570: help_init(void)
  571: {
  572: 	help_cmd.name = _("help");
  573: 	help_cmd.altname = _("?");
  574: 	help_cmd.cfunc = help_f;
  575: 	help_cmd.argmin = 0;
  576: 	help_cmd.argmax = 1;
  577: 	help_cmd.flags = CMD_FLAG_GLOBAL;
  578: 	help_cmd.args = _("[command]");
  579: 	help_cmd.oneline = _("help for one or all commands");
  580: 
  581: 	add_command(&help_cmd);
  582: }

unix.superglobalmegacorp.com