X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fparser.c;h=239c9b99e845e707b4fe0fb378b0c85667d82416;hp=6d26bc38320cc3b8fa692eeae955acb164c3a0b6;hb=3d21af5fd098ba971f835e94fbe1f61b6a994a09;hpb=f24bbb902b0c26f6d0fa28aede5f188e76bff960 diff --git a/lustre/utils/parser.c b/lustre/utils/parser.c index 6d26bc3..239c9b9 100644 --- a/lustre/utils/parser.c +++ b/lustre/utils/parser.c @@ -24,40 +24,32 @@ #include #include #include +#include #include #include -#define READLINE_LIBRARY -#include - -//extern char **completion_matches __P((char *, rl_compentry_func_t *)); -extern void using_history(void); -extern void stifle_history(int); -extern void add_history(char *); - +#include "platform.h" #include "parser.h" -#define CMD_COMPLETE 0 -#define CMD_INCOMPLETE 1 -#define CMD_NONE 2 -#define CMD_AMBIG 3 static command_t * top_level; /* Top level of commands, initialized by * InitParser */ -static command_t * match_tbl; /* Command completion against this table */ static char * parser_prompt = NULL;/* Parser prompt, set by InitParser */ static int done; /* Set to 1 if user types exit or quit */ +static int ignore_errors; /* Normally, the parser will quit when + an error occurs in non-interacive + mode. Setting this to non-zero will + force it to keep buggering on. */ /* static functions */ static char *skipwhitespace(char *s); static char *skiptowhitespace(char *s); static command_t *find_cmd(char *name, command_t cmds[], char **next); -static int process(char *s, char **next, command_t *lookup, command_t **result, char **prev); -static char *command_generator(const char *text, int state); -static char **command_completion(char *text, int start, int end); +static int process(char *s, char **next, command_t *lookup, command_t **result, + char **prev); static void print_commands(char *str, command_t *table); -static char * skipwhitespace(char * s) +static char * skipwhitespace(char * s) { char * t; int len; @@ -68,7 +60,7 @@ static char * skipwhitespace(char * s) } -static char * skiptowhitespace(char * s) +static char * skiptowhitespace(char * s) { char * t; @@ -79,13 +71,13 @@ static char * skiptowhitespace(char * s) static int line2args(char *line, char **argv, int maxargs) { char *arg; - int i = 0; - + int i = 0; + arg = strtok(line, " \t"); if ( arg ) { argv[i] = arg; i++; - } else + } else return 0; while( (arg = strtok(NULL, " \t")) && (i <= maxargs)) { @@ -96,43 +88,36 @@ static int line2args(char *line, char **argv, int maxargs) } /* find a command -- return it if unique otherwise print alternatives */ - static command_t *Parser_findargcmd(char *name, command_t cmds[]) { command_t *cmd; - int i; - - for (i = 0; cmds[i].pc_name; i++) { - cmd = &cmds[i]; - - if (strlen(name) != strlen(cmd->pc_name)) - continue; - - if (strlen(name) == strlen(cmd->pc_name)) { - if (strcmp(name, cmd->pc_name) == 0) - return cmd; - else - continue; - } + for (cmd = cmds; cmd->pc_name; cmd++) { + if (strcmp(name, cmd->pc_name) == 0) + return cmd; } return NULL; } +void Parser_ignore_errors(int ignore) +{ + ignore_errors = ignore; +} + int Parser_execarg(int argc, char **argv, command_t cmds[]) { command_t *cmd; - int i; cmd = Parser_findargcmd(argv[0], cmds); if ( cmd ) { - return (cmd->pc_func)(argc, argv); + int rc = (cmd->pc_func)(argc, argv); + if (rc == CMD_HELP) + fprintf(stderr, "%s\n", cmd->pc_help); + return rc; } else { - printf("Try interactive use without arguments or use one of: "); - for (i=0 ; cmds[i].pc_name ; i++) { - cmd = &cmds[i]; - printf("\"%s\" ", cmd->pc_name); - } + printf("Try interactive use without arguments or use one of:\n"); + for (cmd = cmds; cmd->pc_name; cmd++) + printf("\"%s\"\n", cmd->pc_name); printf("as argument.\n"); } return -1; @@ -141,20 +126,20 @@ int Parser_execarg(int argc, char **argv, command_t cmds[]) /* returns the command_t * (NULL if not found) corresponding to a _partial_ match with the first token in name. It sets *next to point to the following token. Does not modify *name. */ -static command_t * find_cmd(char * name, command_t cmds[], char ** next) +static command_t * find_cmd(char * name, command_t cmds[], char ** next) { int i, len; - - if (!cmds || !name ) + + if (!cmds || !name ) return NULL; - + /* This sets name to point to the first non-white space character, and next to the first whitespace after name, len to the length: do this with strtok*/ name = skipwhitespace(name); *next = skiptowhitespace(name); len = *next - name; - if (len == 0) + if (len == 0) return NULL; for (i = 0; cmds[i].pc_name; i++) { @@ -173,19 +158,37 @@ static int process(char *s, char ** next, command_t *lookup, command_t **result, char **prev) { *result = find_cmd(s, lookup, next); - *prev = s; + *prev = s; /* non existent */ - if ( ! *result ) + if (!*result) return CMD_NONE; /* found entry: is it ambigous, i.e. not exact command name and more than one command in the list matches. Note that find_cmd points to the first ambiguous entry */ - if ( strncasecmp(s, (*result)->pc_name, strlen((*result)->pc_name)) && - find_cmd(s, (*result) + 1, next)) - return CMD_AMBIG; + if (strncasecmp(s, (*result)->pc_name, strlen((*result)->pc_name))) { + char *another_next; + command_t *another_result = find_cmd(s, (*result) + 1, + &another_next); + int found_another = 0; + + while (another_result) { + if (strncasecmp(s, another_result->pc_name, + strlen(another_result->pc_name)) == 0){ + *result = another_result; + *next = another_next; + goto got_it; + } + another_result = find_cmd(s, another_result + 1, + &another_next); + found_another = 1; + } + if (found_another) + return CMD_AMBIG; + } +got_it: /* found a unique command: component or full? */ if ( (*result)->pc_func ) { return CMD_COMPLETE; @@ -193,28 +196,31 @@ static int process(char *s, char ** next, command_t *lookup, if ( *next == '\0' ) { return CMD_INCOMPLETE; } else { - return process(*next, next, (*result)->pc_sub_cmd, result, prev); + return process(*next, next, (*result)->pc_sub_cmd, + result, prev); } } } -static char * command_generator(const char * text, int state) +#ifdef HAVE_LIBREADLINE +static command_t * match_tbl; /* Command completion against this table */ +static char * command_generator(const char * text, int state) { static int index, len; char *name; /* Do we have a match table? */ - if (!match_tbl) + if (!match_tbl) return NULL; - + /* If this is the first time called on this word, state is 0 */ if (!state) { index = 0; len = (int)strlen(text); } - /* Return the next name in the command list that paritally matches test */ + /* Return next name in the command list that paritally matches test */ while ( (name = (match_tbl + index)->pc_name) ) { index++; @@ -228,21 +234,23 @@ static char * command_generator(const char * text, int state) } /* probably called by readline */ -static char **command_completion(char * text, int start, int end) +static char **command_completion(char * text, int start, int end) { - command_t * table; + command_t * table; char * pos; match_tbl = top_level; + for (table = find_cmd(rl_line_buffer, match_tbl, &pos); - table; - table = find_cmd(pos, match_tbl, &pos)) { + table; table = find_cmd(pos, match_tbl, &pos)) + { if (*(pos - 1) == ' ') match_tbl = table->pc_sub_cmd; } - return(completion_matches(text, command_generator)); + return completion_matches(text, command_generator); } +#endif /* take a string and execute the function or print help */ int execute_line(char * line) @@ -254,7 +262,7 @@ int execute_line(char * line) int i; int rc = 0; - switch( process(line, &next, top_level, &cmd, &prev) ) { + switch (process(line, &next, top_level, &cmd, &prev)) { case CMD_AMBIG: fprintf(stderr, "Ambiguous command \'%s\'\nOptions: ", line); while( (ambig = find_cmd(prev, cmd, &tmp)) ) { @@ -279,27 +287,108 @@ int execute_line(char * line) case CMD_COMPLETE: i = line2args(line, argv, MAXARGS); rc = (cmd->pc_func)(i, argv); + + if (rc == CMD_HELP) + fprintf(stderr, "%s\n", cmd->pc_help); + break; } - + return rc; } -/* this is the command execution machine */ -int Parser_commands(void) +int +noop_fn () { - char *line, *s; - int rc = 0; + return (0); +} +/* just in case you're ever in an airplane and discover you + forgot to install readline-dev. :) */ +int init_input() +{ + int interactive = isatty (fileno (stdin)); + +#ifdef HAVE_LIBREADLINE using_history(); stifle_history(HISTORY); - rl_attempted_completion_function = - (CPPFunction *)command_completion; + if (!interactive) + { + rl_prep_term_function = (rl_vintfunc_t *)noop_fn; + rl_deprep_term_function = (rl_voidfunc_t *)noop_fn; + } + + rl_attempted_completion_function = (CPPFunction *)command_completion; rl_completion_entry_function = (void *)command_generator; - +#endif + return interactive; +} + +#ifndef HAVE_LIBREADLINE +#define add_history(s) +char * readline(char * prompt) +{ + int size = 2048; + char *line = malloc(size); + char *ptr = line; + int c; + int eof = 0; + + if (line == NULL) + return NULL; + if (prompt) + printf ("%s", prompt); + + while (1) { + if ((c = fgetc(stdin)) != EOF) { + if (c == '\n') + goto out; + *ptr++ = c; + + if (ptr - line >= size - 1) { + char *tmp; + + size *= 2; + tmp = malloc(size); + if (tmp == NULL) + goto outfree; + memcpy(tmp, line, ptr - line); + ptr = tmp + (ptr - line); + free(line); + line = tmp; + } + } else { + eof = 1; + if (ferror(stdin) || feof(stdin)) + goto outfree; + goto out; + } + } +out: + *ptr = 0; + if (eof && (strlen(line) == 0)) { + free(line); + line = NULL; + } + return line; +outfree: + free(line); + return NULL; +} +#endif + +/* this is the command execution machine */ +int Parser_commands(void) +{ + char *line, *s; + int rc = 0, save_error = 0; + int interactive; + + interactive = init_input(); + while(!done) { - line = readline(parser_prompt); + line = readline(interactive ? parser_prompt : NULL); if (!line) break; @@ -309,15 +398,24 @@ int Parser_commands(void) add_history(s); rc = execute_line(s); } + /* stop on error if not-interactive */ + if (rc != 0 && !interactive) { + if (save_error == 0) + save_error = rc; + if (!ignore_errors) + done = 1; + } free(line); } + if (save_error) + rc = save_error; return rc; } /* sets the parser prompt */ -void Parser_init(char * prompt, command_t * cmds) +void Parser_init(char * prompt, command_t * cmds) { done = 0; top_level = cmds; @@ -326,7 +424,7 @@ void Parser_init(char * prompt, command_t * cmds) } /* frees the parser prompt */ -void Parser_exit(int argc, char *argv[]) +void Parser_exit(int argc, char *argv[]) { done = 1; free(parser_prompt); @@ -351,16 +449,15 @@ int Parser_int(char *s, int *val) } - void Parser_qhelp(int argc, char *argv[]) { printf("Available commands are:\n"); - + print_commands(NULL, top_level); printf("For more help type: help command-name\n"); } -int Parser_help(int argc, char **argv) +int Parser_help(int argc, char **argv) { char line[1024]; char *next, *prev, *tmp; @@ -404,13 +501,19 @@ int Parser_help(int argc, char **argv) break; } return 0; -} +} -/************************************************************************* - * COMMANDS * - *************************************************************************/ +void Parser_printhelp(char *cmd) +{ + char *argv[] = { "help", cmd }; + Parser_help(2, argv); +} + +/************************************************************************* + * COMMANDS * + *************************************************************************/ static void print_commands(char * str, command_t * table) { command_t * cmds; char buf[80]; @@ -431,7 +534,7 @@ static void print_commands(char * str, command_t * table) { } } -char *Parser_getstr(const char *prompt, const char *deft, char *res, +char *Parser_getstr(const char *prompt, const char *deft, char *res, size_t len) { char *line = NULL; @@ -515,9 +618,9 @@ int Parser_getbool(const char *prompt, int deft) assert(theprompt); fflush(stdout); - + if ( deft != 0 && deft != 1 ) { - fprintf(stderr, "Error: Parser_getbool given bad default (%d).\n", + fprintf(stderr, "Error: Parser_getbool given bad default %d\n", deft); assert ( 0 ); } @@ -542,15 +645,15 @@ int Parser_getbool(const char *prompt, int deft) result = 0; break; } - if ( line ) + if ( line ) free(line); fprintf(stdout, "Invalid string. Must start with yY or nN\n"); fflush(stdout); } while ( 1 ); - if ( line ) + if ( line ) free(line); - if ( theprompt ) + if ( theprompt ) free(theprompt); return result; } @@ -560,8 +663,8 @@ long Parser_intarg(const char *inp, const char *prompt, int deft, int min, int max, int base) { long result; - int rc; - + int rc; + rc = Parser_arg2int(inp, &result, base); if ( rc == 0 ) { @@ -575,10 +678,9 @@ long Parser_intarg(const char *inp, const char *prompt, int deft, char *Parser_strarg(char *inp, const char *prompt, const char *deft, char *answer, int len) { - if ( inp == NULL || *inp == '\0' ) { return Parser_getstr(prompt, deft, answer, len); - } else + } else return inp; } @@ -595,14 +697,76 @@ int Parser_arg2int(const char *inp, long *result, int base) if ( *inp != '\0' && *endptr == '\0' ) return 0; - else + else return 1; } +/* Convert human readable size string to and int; "1k" -> 1000 */ +int Parser_size (int *sizep, char *str) { + int size; + char mod[32]; + + switch (sscanf (str, "%d%1[gGmMkK]", &size, mod)) { + default: + return (-1); + + case 1: + *sizep = size; + return (0); + + case 2: + switch (*mod) { + case 'g': + case 'G': + *sizep = size << 30; + return (0); + + case 'm': + case 'M': + *sizep = size << 20; + return (0); + + case 'k': + case 'K': + *sizep = size << 10; + return (0); + + default: + *sizep = size; + return (0); + } + } +} + +/* Convert a string boolean to an int; "enable" -> 1 */ +int Parser_bool (int *b, char *str) { + if (!strcasecmp (str, "no") || + !strcasecmp (str, "n") || + !strcasecmp (str, "off") || + !strcasecmp (str, "down") || + !strcasecmp (str, "disable")) + { + *b = 0; + return (0); + } + + if (!strcasecmp (str, "yes") || + !strcasecmp (str, "y") || + !strcasecmp (str, "on") || + !strcasecmp (str, "up") || + !strcasecmp (str, "enable")) + { + *b = 1; + return (0); + } + + return (-1); +} + int Parser_quit(int argc, char **argv) { argc = argc; argv = argv; - done = 1; + done = 1; return 0; }