//==========================================================================
|
//==========================================================================
|
//
|
//
|
// parse.c
|
// parse.c
|
//
|
//
|
// RedBoot command line parsing routine
|
// RedBoot command line parsing routine
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
// ####ECOSGPLCOPYRIGHTBEGIN####
|
// ####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos 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
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later
|
// Software Foundation; either version 2 or (at your option) any later
|
// version.
|
// version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use
|
// As a special exception, if other files instantiate templates or use
|
// macros or inline functions from this file, or you compile this file
|
// macros or inline functions from this file, or you compile this file
|
// and link it with other works to produce a work based on this file,
|
// and link it with other works to produce a work based on this file,
|
// this file does not by itself cause the resulting work to be covered by
|
// this file does not by itself cause the resulting work to be covered by
|
// the GNU General Public License. However the source code for this file
|
// the GNU General Public License. However the source code for this file
|
// must still be made available in accordance with section (3) of the GNU
|
// must still be made available in accordance with section (3) of the GNU
|
// General Public License v2.
|
// General Public License v2.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based
|
// This exception does not invalidate any other reasons why a work based
|
// on this file might be covered by the GNU General Public License.
|
// on this file might be covered by the GNU General Public License.
|
// -------------------------------------------
|
// -------------------------------------------
|
// ####ECOSGPLCOPYRIGHTEND####
|
// ####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): gthomas
|
// Author(s): gthomas
|
// Contributors: gthomas, eCosCentric
|
// Contributors: gthomas, eCosCentric
|
// Date: 2000-07-14
|
// Date: 2000-07-14
|
// Purpose:
|
// Purpose:
|
// Description:
|
// Description:
|
//
|
//
|
// This code is part of RedBoot (tm).
|
// This code is part of RedBoot (tm).
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
|
|
// #include <redboot.h>
|
// #include <redboot.h>
|
#include "lib_dbg_sh.h"
|
#include "lib_dbg_sh.h"
|
#include "dbg_sh.h"
|
#include "dbg_sh.h"
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
|
|
#include <cyg/hal/hal_arch.h>
|
#include <cyg/hal/hal_arch.h>
|
#include <cyg/hal/hal_intr.h>
|
#include <cyg/hal/hal_intr.h>
|
#include <cyg/hal/hal_cache.h>
|
#include <cyg/hal/hal_cache.h>
|
#include CYGHWR_MEMORY_LAYOUT_H
|
#include CYGHWR_MEMORY_LAYOUT_H
|
#include <cyg/hal/hal_tables.h>
|
#include <cyg/hal/hal_tables.h>
|
|
|
|
|
struct cmd *cmd_search(struct cmd *tab, struct cmd *tabend, char *arg);
|
struct cmd *cmd_search(struct cmd *tab, struct cmd *tabend, char *arg);
|
bool parse_num(char *s, unsigned long *val, char **es, char *delim);
|
bool parse_num(char *s, unsigned long *val, char **es, char *delim);
|
bool parse_bool(char *s, bool *val);
|
bool parse_bool(char *s, bool *val);
|
|
|
|
|
// Define table boundaries
|
// Define table boundaries
|
extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
|
extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
|
|
|
//
|
//
|
// Scan through an input line and break it into "arguments". These
|
// Scan through an input line and break it into "arguments". These
|
// are space delimited strings. Return a structure which points to
|
// are space delimited strings. Return a structure which points to
|
// the strings, similar to a Unix program. Multiple commands in the line
|
// the strings, similar to a Unix program. Multiple commands in the line
|
// are separated by ; similar to sh. If we find a semi we stop processing the
|
// are separated by ; similar to sh. If we find a semi we stop processing the
|
// line, terminate the current command with a null and return the start
|
// line, terminate the current command with a null and return the start
|
// of the next command in *line. parse() can then be called again to
|
// of the next command in *line. parse() can then be called again to
|
// process the next command on the line.
|
// process the next command on the line.
|
// Note: original input is destroyed by replacing the delimiters with
|
// Note: original input is destroyed by replacing the delimiters with
|
// null ('\0') characters for ease of use.
|
// null ('\0') characters for ease of use.
|
//
|
//
|
struct cmd *
|
struct cmd *
|
parse(char **line, int *argc, char **argv)
|
parse(char **line, int *argc, char **argv)
|
{
|
{
|
char *cp = *line;
|
char *cp = *line;
|
char *pp;
|
char *pp;
|
int indx = 0;
|
int indx = 0;
|
int semi = 0;
|
int semi = 0;
|
|
|
while (*cp) {
|
while (*cp) {
|
// Skip leading spaces
|
// Skip leading spaces
|
while (*cp && *cp == ' ') cp++;
|
while (*cp && *cp == ' ') cp++;
|
if (!*cp) {
|
if (!*cp) {
|
break; // Line ended with a string of spaces
|
break; // Line ended with a string of spaces
|
}
|
}
|
if (*cp == ';') {
|
if (*cp == ';') {
|
*cp = '\0';
|
*cp = '\0';
|
semi=1;
|
semi=1;
|
break;
|
break;
|
}
|
}
|
if (indx < MAX_ARGV) {
|
if (indx < MAX_ARGV) {
|
argv[indx++] = cp;
|
argv[indx++] = cp;
|
} else {
|
} else {
|
printf("Too many arguments - stopped at: '%s'\n", cp);
|
printf("Too many arguments - stopped at: '%s'\n", cp);
|
}
|
}
|
while (*cp) {
|
while (*cp) {
|
if (*cp == ' ') {
|
if (*cp == ' ') {
|
*cp++ = '\0';
|
*cp++ = '\0';
|
break;
|
break;
|
} else if (*cp == ';') {
|
} else if (*cp == ';') {
|
break;
|
break;
|
} else if (*cp == '"') {
|
} else if (*cp == '"') {
|
// Swallow quote, scan till following one
|
// Swallow quote, scan till following one
|
if (argv[indx-1] == cp) {
|
if (argv[indx-1] == cp) {
|
argv[indx-1] = ++cp;
|
argv[indx-1] = ++cp;
|
}
|
}
|
pp = cp;
|
pp = cp;
|
while (*cp && *cp != '"') {
|
while (*cp && *cp != '"') {
|
if (*cp == '\\') {
|
if (*cp == '\\') {
|
// Skip over escape - allows for escaped '"'
|
// Skip over escape - allows for escaped '"'
|
cp++;
|
cp++;
|
}
|
}
|
// Move string to swallow escapes
|
// Move string to swallow escapes
|
*pp++ = *cp++;
|
*pp++ = *cp++;
|
}
|
}
|
if (!*cp) {
|
if (!*cp) {
|
printf("Unbalanced string!\n");
|
printf("Unbalanced string!\n");
|
} else {
|
} else {
|
if (pp != cp) *pp = '\0';
|
if (pp != cp) *pp = '\0';
|
*cp++ = '\0';
|
*cp++ = '\0';
|
break;
|
break;
|
}
|
}
|
} else {
|
} else {
|
cp++;
|
cp++;
|
}
|
}
|
}
|
}
|
}
|
}
|
if (semi) {
|
if (semi) {
|
*line = cp + 1;
|
*line = cp + 1;
|
} else {
|
} else {
|
*line = cp;
|
*line = cp;
|
}
|
}
|
*argc = indx;
|
*argc = indx;
|
return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
|
return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
|
}
|
}
|
|
|
//
|
//
|
// Search through a list of commands
|
// Search through a list of commands
|
//
|
//
|
struct cmd *
|
struct cmd *
|
cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
|
cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
|
{
|
{
|
int cmd_len;
|
int cmd_len;
|
struct cmd *cmd, *cmd2;
|
struct cmd *cmd, *cmd2;
|
// Search command table
|
// Search command table
|
cmd_len = strlen(arg);
|
cmd_len = strlen(arg);
|
cmd = tab;
|
cmd = tab;
|
while (cmd != tabend) {
|
while (cmd != tabend) {
|
if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
|
if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
|
if (strlen(cmd->str) > cmd_len) {
|
if (strlen(cmd->str) > cmd_len) {
|
// Check for ambiguous commands here
|
// Check for ambiguous commands here
|
// Note: If there are commands which are not length-unique
|
// Note: If there are commands which are not length-unique
|
// then this check will be invalid. E.g. "du" and "dump"
|
// then this check will be invalid. E.g. "du" and "dump"
|
bool first = true;
|
bool first = true;
|
cmd2 = tab;
|
cmd2 = tab;
|
while (cmd2 != tabend) {
|
while (cmd2 != tabend) {
|
if ((cmd != cmd2) &&
|
if ((cmd != cmd2) &&
|
(strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
|
(strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
|
if (first) {
|
if (first) {
|
printf("Ambiguous command '%s', choices are: %s",
|
printf("Ambiguous command '%s', choices are: %s",
|
arg, cmd->str);
|
arg, cmd->str);
|
first = false;
|
first = false;
|
}
|
}
|
printf(" %s", cmd2->str);
|
printf(" %s", cmd2->str);
|
}
|
}
|
cmd2++;
|
cmd2++;
|
}
|
}
|
if (!first) {
|
if (!first) {
|
// At least one ambiguity found - fail the lookup
|
// At least one ambiguity found - fail the lookup
|
printf("\n");
|
printf("\n");
|
return (struct cmd *)0;
|
return (struct cmd *)0;
|
}
|
}
|
}
|
}
|
return cmd;
|
return cmd;
|
}
|
}
|
cmd++;
|
cmd++;
|
}
|
}
|
return (struct cmd *)0;
|
return (struct cmd *)0;
|
}
|
}
|
|
|
void
|
void
|
cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
|
cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
|
{
|
{
|
struct cmd *cmd;
|
struct cmd *cmd;
|
|
|
printf("Usage:\n");
|
printf("Usage:\n");
|
for (cmd = tab; cmd != tabend; cmd++) {
|
for (cmd = tab; cmd != tabend; cmd++) {
|
printf(" %s%s %s\n", prefix, cmd->str, cmd->usage);
|
printf(" %s%s %s\n", prefix, cmd->str, cmd->usage);
|
}
|
}
|
}
|
}
|
|
|
//
|
//
|
// Handle illegal memory accesses (and other abort conditions)
|
// Handle illegal memory accesses (and other abort conditions)
|
//
|
//
|
static hal_jmp_buf error_jmpbuf;
|
static hal_jmp_buf error_jmpbuf;
|
static cyg_bool redboot_exec_call = false;
|
static cyg_bool redboot_exec_call = false;
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
__externC void* volatile __mem_fault_handler;
|
__externC void* volatile __mem_fault_handler;
|
|
|
static void error_handler(void)
|
static void error_handler(void)
|
{
|
{
|
hal_longjmp(error_jmpbuf, 1);
|
hal_longjmp(error_jmpbuf, 1);
|
}
|
}
|
#endif
|
#endif
|
|
|
// Routine to allow code to invoke RedBoot commands. This is useful
|
// Routine to allow code to invoke RedBoot commands. This is useful
|
// during initialization and in platform specific code.
|
// during initialization and in platform specific code.
|
//
|
//
|
// Call it like this:
|
// Call it like this:
|
//
|
//
|
// result = redboot_exec( "load", "-m", "file", "foo", 0 );
|
// result = redboot_exec( "load", "-m", "file", "foo", 0 );
|
//
|
//
|
// Note the terminating zero. The result will be zero if the command
|
// Note the terminating zero. The result will be zero if the command
|
// succeeded, and <0 if something went wrong.
|
// succeeded, and <0 if something went wrong.
|
|
|
#define ARGV_MAX 20
|
#define ARGV_MAX 20
|
int redboot_exec( char *command, ... )
|
int redboot_exec( char *command, ... )
|
{
|
{
|
int argc;
|
int argc;
|
char *argv[ARGV_MAX+1];
|
char *argv[ARGV_MAX+1];
|
va_list ap;
|
va_list ap;
|
struct cmd *cmd;
|
struct cmd *cmd;
|
int result = 0;
|
int result = 0;
|
|
|
va_start(ap, command);
|
va_start(ap, command);
|
|
|
argv[0] = command;
|
argv[0] = command;
|
for( argc = 1; argc < ARGV_MAX; argc++ )
|
for( argc = 1; argc < ARGV_MAX; argc++ )
|
{
|
{
|
char *arg = va_arg(ap, char *);
|
char *arg = va_arg(ap, char *);
|
if( arg == 0 )
|
if( arg == 0 )
|
break;
|
break;
|
argv[argc] = arg;
|
argv[argc] = arg;
|
}
|
}
|
argv[argc] = NULL;
|
argv[argc] = NULL;
|
|
|
if(( cmd = cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, command) ))
|
if(( cmd = cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, command) ))
|
{
|
{
|
// Try to handle aborts - messy because of the stack unwinding...
|
// Try to handle aborts - messy because of the stack unwinding...
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
__mem_fault_handler = error_handler;
|
__mem_fault_handler = error_handler;
|
#endif
|
#endif
|
redboot_exec_call = true;
|
redboot_exec_call = true;
|
if (hal_setjmp(error_jmpbuf))
|
if (hal_setjmp(error_jmpbuf))
|
result = -1;
|
result = -1;
|
else
|
else
|
(cmd->fun)(argc, argv);
|
(cmd->fun)(argc, argv);
|
|
|
redboot_exec_call = false;
|
redboot_exec_call = false;
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
__mem_fault_handler = 0;
|
__mem_fault_handler = 0;
|
#endif
|
#endif
|
}
|
}
|
else
|
else
|
result = -1;
|
result = -1;
|
|
|
va_end(ap);
|
va_end(ap);
|
|
|
return result;
|
return result;
|
}
|
}
|
|
|
// externC void err_printf( const char *fmt, ... )
|
// externC void err_printf( const char *fmt, ... )
|
// {
|
// {
|
// va_list ap;
|
// va_list ap;
|
//
|
//
|
// va_start(ap, fmt);
|
// va_start(ap, fmt);
|
|
|
// vprintf( fmt, ap );
|
// vprintf( fmt, ap );
|
|
|
// va_end(ap);
|
// va_end(ap);
|
|
|
// // If we are not in redboot_exec() just return as usual. If we are
|
// // If we are not in redboot_exec() just return as usual. If we are
|
// // inside a call to redboot_exec(), longjump out to terminate the command.
|
// // inside a call to redboot_exec(), longjump out to terminate the command.
|
//
|
//
|
// if( redboot_exec_call )
|
// if( redboot_exec_call )
|
// {
|
// {
|
// printf("err_printf: aborting command\n");
|
// printf("err_printf: aborting command\n");
|
// hal_longjmp(error_jmpbuf, 1);
|
// hal_longjmp(error_jmpbuf, 1);
|
// }
|
// }
|
// }
|
// }
|
|
|
|
|
// Option processing
|
// Option processing
|
|
|
// Initialize option table entry (required because these entries
|
// Initialize option table entry (required because these entries
|
// may have dynamic contents, thus cannot be statically initialized)
|
// may have dynamic contents, thus cannot be statically initialized)
|
//
|
//
|
void
|
void
|
init_opts(struct option_info *opts, char flag, bool takes_arg,
|
init_opts(struct option_info *opts, char flag, bool takes_arg,
|
int arg_type, void *arg, bool *arg_set, char *name)
|
int arg_type, void *arg, bool *arg_set, char *name)
|
{
|
{
|
opts->flag = flag;
|
opts->flag = flag;
|
opts->takes_arg = takes_arg;
|
opts->takes_arg = takes_arg;
|
opts->arg_type = arg_type,
|
opts->arg_type = arg_type,
|
opts->arg = arg;
|
opts->arg = arg;
|
opts->arg_set = arg_set;
|
opts->arg_set = arg_set;
|
opts->name = name;
|
opts->name = name;
|
}
|
}
|
|
|
//
|
//
|
// Scan command line arguments (argc/argv), processing options, etc.
|
// Scan command line arguments (argc/argv), processing options, etc.
|
//
|
//
|
bool
|
bool
|
scan_opts(int argc, char *argv[], int first,
|
scan_opts(int argc, char *argv[], int first,
|
struct option_info *opts, int num_opts,
|
struct option_info *opts, int num_opts,
|
void *def_arg, int def_arg_type, char *def_descr)
|
void *def_arg, int def_arg_type, char *def_descr)
|
{
|
{
|
bool ret = true;
|
bool ret = true;
|
bool flag_ok;
|
bool flag_ok;
|
bool def_arg_set = false;
|
bool def_arg_set = false;
|
int i, j;
|
int i, j;
|
char c, *s;
|
char c, *s;
|
struct option_info *opt;
|
struct option_info *opt;
|
|
|
if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
|
if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
|
*(char **)def_arg = (char *)0;
|
*(char **)def_arg = (char *)0;
|
}
|
}
|
opt = opts;
|
opt = opts;
|
for (j = 0; j < num_opts; j++, opt++) {
|
for (j = 0; j < num_opts; j++, opt++) {
|
if (opt->arg_set) {
|
if (opt->arg_set) {
|
*opt->arg_set = false;
|
*opt->arg_set = false;
|
}
|
}
|
if (!opt->takes_arg) {
|
if (!opt->takes_arg) {
|
switch (opt->arg_type) {
|
switch (opt->arg_type) {
|
case OPTION_ARG_TYPE_NUM:
|
case OPTION_ARG_TYPE_NUM:
|
*(int *)opt->arg = 0;
|
*(int *)opt->arg = 0;
|
break;
|
break;
|
case OPTION_ARG_TYPE_FLG:
|
case OPTION_ARG_TYPE_FLG:
|
*(bool *)opt->arg = false;
|
*(bool *)opt->arg = false;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
for (i = first; i < argc; i++) {
|
for (i = first; i < argc; i++) {
|
if (argv[i][0] == '-') {
|
if (argv[i][0] == '-') {
|
c = argv[i][1];
|
c = argv[i][1];
|
flag_ok = false;
|
flag_ok = false;
|
opt = opts;
|
opt = opts;
|
for (j = 0; j < num_opts; j++, opt++) {
|
for (j = 0; j < num_opts; j++, opt++) {
|
if (c == opt->flag) {
|
if (c == opt->flag) {
|
if (opt->arg_set && *opt->arg_set) {
|
if (opt->arg_set && *opt->arg_set) {
|
printf("** Error: %s already specified\n", opt->name);
|
printf("** Error: %s already specified\n", opt->name);
|
ret = false;
|
ret = false;
|
}
|
}
|
if (opt->takes_arg) {
|
if (opt->takes_arg) {
|
if (argv[i][2] == '=') {
|
if (argv[i][2] == '=') {
|
s = &argv[i][3];
|
s = &argv[i][3];
|
} else {
|
} else {
|
s = argv[i+1];
|
s = argv[i+1];
|
i++;
|
i++;
|
}
|
}
|
switch (opt->arg_type) {
|
switch (opt->arg_type) {
|
case OPTION_ARG_TYPE_NUM:
|
case OPTION_ARG_TYPE_NUM:
|
if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
|
if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
|
printf("** Error: invalid number '%s' for %s\n",
|
printf("** Error: invalid number '%s' for %s\n",
|
s, opt->name);
|
s, opt->name);
|
ret = false;
|
ret = false;
|
}
|
}
|
break;
|
break;
|
case OPTION_ARG_TYPE_STR:
|
case OPTION_ARG_TYPE_STR:
|
*(char **)opt->arg = s;
|
*(char **)opt->arg = s;
|
break;
|
break;
|
}
|
}
|
*opt->arg_set = true;
|
*opt->arg_set = true;
|
} else {
|
} else {
|
switch (opt->arg_type) {
|
switch (opt->arg_type) {
|
case OPTION_ARG_TYPE_NUM:
|
case OPTION_ARG_TYPE_NUM:
|
*(int *)opt->arg = *(int *)opt->arg + 1;
|
*(int *)opt->arg = *(int *)opt->arg + 1;
|
break;
|
break;
|
case OPTION_ARG_TYPE_FLG:
|
case OPTION_ARG_TYPE_FLG:
|
*(bool *)opt->arg = true;
|
*(bool *)opt->arg = true;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
flag_ok = true;
|
flag_ok = true;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if (!flag_ok) {
|
if (!flag_ok) {
|
printf("** Error: invalid flag '%c'\n", c);
|
printf("** Error: invalid flag '%c'\n", c);
|
ret = false;
|
ret = false;
|
}
|
}
|
} else {
|
} else {
|
if (def_arg) {
|
if (def_arg) {
|
if (def_arg_set) {
|
if (def_arg_set) {
|
printf("** Error: %s already specified\n", def_descr);
|
printf("** Error: %s already specified\n", def_descr);
|
ret = false;
|
ret = false;
|
}
|
}
|
switch (def_arg_type) {
|
switch (def_arg_type) {
|
case OPTION_ARG_TYPE_NUM:
|
case OPTION_ARG_TYPE_NUM:
|
if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
|
if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
|
printf("** Error: invalid number '%s' for %s\n",
|
printf("** Error: invalid number '%s' for %s\n",
|
argv[i], def_descr);
|
argv[i], def_descr);
|
ret = false;
|
ret = false;
|
}
|
}
|
break;
|
break;
|
case OPTION_ARG_TYPE_STR:
|
case OPTION_ARG_TYPE_STR:
|
*(char **)def_arg = argv[i];
|
*(char **)def_arg = argv[i];
|
break;
|
break;
|
}
|
}
|
def_arg_set = true;
|
def_arg_set = true;
|
} else {
|
} else {
|
printf("** Error: no default/non-flag arguments supported\n");
|
printf("** Error: no default/non-flag arguments supported\n");
|
ret = false;
|
ret = false;
|
}
|
}
|
}
|
}
|
}
|
}
|
return ret;
|
return ret;
|
}
|
}
|
|
|
//
|
//
|
// Parse (scan) a number
|
// Parse (scan) a number
|
//
|
//
|
bool
|
bool
|
parse_num(char *s, unsigned long *val, char **es, char *delim)
|
parse_num(char *s, unsigned long *val, char **es, char *delim)
|
{
|
{
|
bool first = true;
|
bool first = true;
|
int radix = 10;
|
int radix = 10;
|
char c;
|
char c;
|
unsigned long result = 0;
|
unsigned long result = 0;
|
int digit;
|
int digit;
|
|
|
while (*s == ' ') s++;
|
while (*s == ' ') s++;
|
while (*s) {
|
while (*s) {
|
if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
|
if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
|
radix = 16;
|
radix = 16;
|
s += 2;
|
s += 2;
|
}
|
}
|
first = false;
|
first = false;
|
c = *s++;
|
c = *s++;
|
if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
|
if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
|
// Valid digit
|
// Valid digit
|
#ifdef CYGPKG_HAL_MIPS
|
#ifdef CYGPKG_HAL_MIPS
|
// FIXME: tx49 compiler generates 0x2539018 for MUL which
|
// FIXME: tx49 compiler generates 0x2539018 for MUL which
|
// isn't any good.
|
// isn't any good.
|
if (16 == radix)
|
if (16 == radix)
|
result = result << 4;
|
result = result << 4;
|
else
|
else
|
result = 10 * result;
|
result = 10 * result;
|
result += digit;
|
result += digit;
|
#else
|
#else
|
result = (result * radix) + digit;
|
result = (result * radix) + digit;
|
#endif
|
#endif
|
} else {
|
} else {
|
if (delim != (char *)0) {
|
if (delim != (char *)0) {
|
// See if this character is one of the delimiters
|
// See if this character is one of the delimiters
|
char *dp = delim;
|
char *dp = delim;
|
while (*dp && (c != *dp)) dp++;
|
while (*dp && (c != *dp)) dp++;
|
if (*dp) break; // Found a good delimiter
|
if (*dp) break; // Found a good delimiter
|
}
|
}
|
return false; // Malformatted number
|
return false; // Malformatted number
|
}
|
}
|
}
|
}
|
*val = result;
|
*val = result;
|
if (es != (char **)0) {
|
if (es != (char **)0) {
|
*es = s;
|
*es = s;
|
}
|
}
|
return true;
|
return true;
|
}
|
}
|
|
|
bool
|
bool
|
parse_bool(char *s, bool *val)
|
parse_bool(char *s, bool *val)
|
{
|
{
|
while (*s == ' ') s++;
|
while (*s == ' ') s++;
|
if ((*s == 't') || (*s == 'T')) {
|
if ((*s == 't') || (*s == 'T')) {
|
char *p = "rue";
|
char *p = "rue";
|
char *P = "RUE";
|
char *P = "RUE";
|
// check for (partial) rest of the word and no extra including the
|
// check for (partial) rest of the word and no extra including the
|
// terminating zero. "tru" will match; "truef" will not.
|
// terminating zero. "tru" will match; "truef" will not.
|
while ( *++s ) {
|
while ( *++s ) {
|
if ( *p != *s && *P != *s ) return false;
|
if ( *p != *s && *P != *s ) return false;
|
p++; P++;
|
p++; P++;
|
}
|
}
|
*val = true;
|
*val = true;
|
} else
|
} else
|
if ((*s == 'f') || (*s == 'F')) {
|
if ((*s == 'f') || (*s == 'F')) {
|
char *p = "alse";
|
char *p = "alse";
|
char *P = "ALSE";
|
char *P = "ALSE";
|
while ( *++s ) {
|
while ( *++s ) {
|
if ( *p != *s && *P != *s ) return false;
|
if ( *p != *s && *P != *s ) return false;
|
p++; P++;
|
p++; P++;
|
}
|
}
|
*val = false;
|
*val = false;
|
} else {
|
} else {
|
return false;
|
return false;
|
}
|
}
|
return true;
|
return true;
|
}
|
}
|
|
|
|
|