/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2001 Cluster File Systems, Inc.
+ * GPL HEADER START
*
- * This file is part of Lustre, http://www.sf.net/projects/lustre/
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Lustre is distributed in the hope that it will 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.
+ * This program is distributed in the hope that it will 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
*
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <assert.h>
-#include <config.h>
-#ifdef HAVE_LIBREADLINE
-#define READLINE_LIBRARY
-#include <readline/readline.h>
-
-//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 *);
-#endif
-
+#include "platform.h"
#include "parser.h"
static command_t * top_level; /* Top level of commands, initialized by
* InitParser */
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 */
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;
}
-static char * skiptowhitespace(char * s)
+static char * skiptowhitespace(char * s)
{
char * t;
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)) {
return NULL;
}
+void Parser_ignore_errors(int ignore)
+{
+ ignore_errors = ignore;
+}
+
+/* Returns:
+ 0 on success
+ >0 CMD_* values
+ <0 errnos
+*/
int Parser_execarg(int argc, char **argv, command_t cmds[])
{
command_t *cmd;
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:\n");
for (cmd = cmds; cmd->pc_name; cmd++)
- printf("\"%s\" ", cmd->pc_name);
- printf("\nas argument.\n");
+ printf("\"%s\"\n", cmd->pc_name);
+ printf("as argument.\n");
}
- return -1;
+ return -EINVAL;
}
/* 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++) {
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;
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);
}
}
}
/* probably called by readline */
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
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)) ) {
return (0);
}
-/* just in case you're ever in an airplane and discover you
+/* just in case you're ever in an airplane and discover you
forgot to install readline-dev. :) */
-int init_input()
+int init_input()
{
int interactive = isatty (fileno (stdin));
rl_attempted_completion_function = (CPPFunction *)command_completion;
rl_completion_entry_function = (void *)command_generator;
-#endif
+#endif
return interactive;
}
#ifndef HAVE_LIBREADLINE
#define add_history(s)
-char * readline(char * prompt)
+char * readline(char * prompt)
{
- char line[2048];
- int n;
- char * ret = NULL;
+ 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);
- fgets(line, sizeof(line), stdin);
- n = strlen(line);
- if (n && line[n-1] == '\n')
- line[--n] = '\0';
- if (n == 0 && feof(stdin)) {
- ret = NULL;
- } else
- ret = strdup(line);
- return ret;
+
+ 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
int Parser_commands(void)
{
char *line, *s;
- int rc = 0;
+ int rc = 0, save_error = 0;
int interactive;
-
+
interactive = init_input();
while(!done) {
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;
}
/* frees the parser prompt */
-void Parser_exit(int argc, char *argv[])
+void Parser_exit(int argc, char *argv[])
{
done = 1;
free(parser_prompt);
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;
break;
}
return 0;
-}
+}
void Parser_printhelp(char *cmd)
{
- char *argv[] = { "help", cmd };
+ char *argv[] = { "help", cmd };
Parser_help(2, argv);
}
/*************************************************************************
- * COMMANDS *
- *************************************************************************/
-
-
+ * COMMANDS *
+ *************************************************************************/
static void print_commands(char * str, command_t * table) {
command_t * cmds;
char buf[80];
}
}
-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;
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 );
}
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;
}
int min, int max, int base)
{
long result;
- int rc;
-
+ int rc;
+
rc = Parser_arg2int(inp, &result, base);
if ( rc == 0 ) {
{
if ( inp == NULL || *inp == '\0' ) {
return Parser_getstr(prompt, deft, answer, len);
- } else
+ } else
return inp;
}
if ( *inp != '\0' && *endptr == '\0' )
return 0;
- else
+ else
return 1;
}
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);
}