Commit bbe7110f authored by oharboe's avatar oharboe
Browse files

duane ellis: (A) a new concept called "Name Value Pair" or NVP, in simple...

duane ellis: (A) a new concept called "Name Value Pair" or NVP, in simple terms: Think: "String" and "Value". There can be many strings - all related to a single value, for examle: "T", "t", "y", "1", "yes", all can represent "truth", the reverse mapping is more simplistic - the first matching number wins.

(B) a new "getopt" like feature for Jim - that simplifies argument parsing in complex functions, normally this would be used in conjunction with either an NVP table of options, or a more simpler Enumeration  table.  In contrast to the GNU "getopt" package, this is more of a "object model or code oriented" solution then a pure data structure used by GNU getopt, or the main stream Tcl/Tk option processing.

git-svn-id: svn://svn.berlios.de/openocd/trunk@936 b42882b7-edfa-0310-969c-e2dbd0fdcd60
parent 5227c98f
......@@ -2510,9 +2510,9 @@ int qsortCompareStringPointers(const void *a, const void *b)
}
int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
const char **tablePtr, int *indexPtr, const char *name, int flags)
const char * const *tablePtr, int *indexPtr, const char *name, int flags)
{
const char **entryPtr = NULL;
const char * const *entryPtr = NULL;
char **tablePtrSorted;
int i, count = 0;
......@@ -2547,6 +2547,29 @@ int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
return JIM_ERR;
}
int Jim_GetNvp(Jim_Interp *interp,
Jim_Obj *objPtr,
const Jim_Nvp *nvp_table,
const Jim_Nvp ** result)
{
Jim_Nvp *n;
int e;
e = Jim_Nvp_name2value_obj( interp, nvp_table, objPtr, &n );
if( e == JIM_ERR ){
return e;
}
/* Success? found? */
if( n->name ){
/* remove const */
*result = (Jim_Nvp *)n;
return JIM_OK;
} else {
return JIM_ERR;
}
}
/* -----------------------------------------------------------------------------
* Source Object
*
......@@ -9151,6 +9174,37 @@ void JimRegisterCoreApi(Jim_Interp *interp)
JIM_REGISTER_API(StackPop);
JIM_REGISTER_API(StackPeek);
JIM_REGISTER_API(FreeStackElements);
JIM_REGISTER_API(fprintf );
JIM_REGISTER_API(vfprintf );
JIM_REGISTER_API(fwrite );
JIM_REGISTER_API(fread );
JIM_REGISTER_API(fflush );
JIM_REGISTER_API(fgets );
JIM_REGISTER_API(GetNvp);
JIM_REGISTER_API(Nvp_name2value);
JIM_REGISTER_API(Nvp_name2value_simple);
JIM_REGISTER_API(Nvp_name2value_obj);
JIM_REGISTER_API(Nvp_name2value_nocase);
JIM_REGISTER_API(Nvp_name2value_obj_nocase);
JIM_REGISTER_API(Nvp_value2name);
JIM_REGISTER_API(Nvp_value2name_simple);
JIM_REGISTER_API(Nvp_value2name_obj);
JIM_REGISTER_API(GetOpt_Setup);
JIM_REGISTER_API(GetOpt_Debug);
JIM_REGISTER_API(GetOpt_Obj);
JIM_REGISTER_API(GetOpt_String);
JIM_REGISTER_API(GetOpt_Double);
JIM_REGISTER_API(GetOpt_Wide);
JIM_REGISTER_API(GetOpt_Nvp);
JIM_REGISTER_API(GetOpt_NvpUnknown);
JIM_REGISTER_API(GetOpt_Enum);
JIM_REGISTER_API(Debug_ArgvString);
JIM_REGISTER_API(SetResult_sprintf);
JIM_REGISTER_API(SetResult_NvpUnknown);
}
/* -----------------------------------------------------------------------------
......@@ -12162,3 +12216,404 @@ char* Jim_fgets( Jim_Interp *interp, char *s, int size, void *cookie )
}
return (*(interp->cb_fgets))( s, size, cookie );
}
Jim_Nvp *
Jim_Nvp_name2value_simple( const Jim_Nvp *p, const char *name )
{
while( p->name ){
if( 0 == strcmp( name, p->name ) ){
break;
}
p++;
}
return ((Jim_Nvp *)(p));
}
Jim_Nvp *
Jim_Nvp_name2value_nocase_simple( const Jim_Nvp *p, const char *name )
{
while( p->name ){
if( 0 == strcasecmp( name, p->name ) ){
break;
}
p++;
}
return ((Jim_Nvp *)(p));
}
int
Jim_Nvp_name2value_obj( Jim_Interp *interp,
const Jim_Nvp *p,
Jim_Obj *o,
Jim_Nvp **result )
{
return Jim_Nvp_name2value( interp, p, Jim_GetString( o, NULL ), result );
}
int
Jim_Nvp_name2value( Jim_Interp *interp,
const Jim_Nvp *_p,
const char *name,
Jim_Nvp **result)
{
const Jim_Nvp *p;
p = Jim_Nvp_name2value_simple( _p, name );
/* result */
if( result ){
*result = (Jim_Nvp *)(p);
}
/* found? */
if( p->name ){
return JIM_OK;
} else {
return JIM_ERR;
}
}
int
Jim_Nvp_name2value_obj_nocase( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **puthere )
{
return Jim_Nvp_name2value_nocase( interp, p, Jim_GetString( o, NULL ), puthere );
}
int
Jim_Nvp_name2value_nocase( Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **puthere )
{
const Jim_Nvp *p;
p = Jim_Nvp_name2value_nocase_simple( _p, name );
if( puthere ){
*puthere = (Jim_Nvp *)(p);
}
/* found */
if( p->name ){
return JIM_OK;
} else {
return JIM_ERR;
}
}
int
Jim_Nvp_value2name_obj( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result )
{
int e;;
jim_wide w;
e = Jim_GetWide( interp, o, &w );
if( e != JIM_OK ){
return e;
}
return Jim_Nvp_value2name( interp, p, w, result );
}
Jim_Nvp *
Jim_Nvp_value2name_simple( const Jim_Nvp *p, int value )
{
while( p->name ){
if( value == p->value ){
break;
}
p++;
}
return ((Jim_Nvp *)(p));
}
int
Jim_Nvp_value2name( Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp **result )
{
const Jim_Nvp *p;
p = Jim_Nvp_value2name_simple( _p, value );
if( result ){
*result = (Jim_Nvp *)(p);
}
if( p->name ){
return JIM_OK;
} else {
return JIM_ERR;
}
}
int
Jim_GetOpt_Setup( Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj * const * argv)
{
memset( p, 0, sizeof(*p) );
p->interp = interp;
p->argc = argc;
p->argv = argv;
return JIM_OK;
}
void
Jim_GetOpt_Debug( Jim_GetOptInfo *p )
{
int x;
Jim_fprintf( p->interp, p->interp->cookie_stderr, "---args---\n");
for( x = 0 ; x < p->argc ; x++ ){
Jim_fprintf( p->interp, p->interp->cookie_stderr,
"%2d) %s\n",
x,
Jim_GetString( p->argv[x], NULL ) );
}
Jim_fprintf( p->interp, p->interp->cookie_stderr, "-------\n");
}
int
Jim_GetOpt_Obj( Jim_GetOptInfo *goi, Jim_Obj **puthere )
{
Jim_Obj *o;
o = NULL; // failure
if( goi->argc ){
// success
o = goi->argv[0];
goi->argc -= 1;
goi->argv += 1;
}
if( puthere ){
*puthere = o;
}
if( o != NULL ){
return JIM_OK;
} else {
return JIM_ERR;
}
}
int
Jim_GetOpt_String( Jim_GetOptInfo *goi, char **puthere, int *len )
{
int r;
Jim_Obj *o;
const char *cp;
r = Jim_GetOpt_Obj( goi, &o );
if( r == JIM_OK ){
cp = Jim_GetString( o, len );
if( puthere ){
/* remove const */
*puthere = (char *)(cp);
}
}
return r;
}
int
Jim_GetOpt_Double( Jim_GetOptInfo *goi, double *puthere )
{
int r;
Jim_Obj *o;
double _safe;
if( puthere == NULL ){
puthere = &_safe;
}
r = Jim_GetOpt_Obj( goi, &o );
if( r == JIM_OK ){
r = Jim_GetDouble( goi->interp, o, puthere );
if( r != JIM_OK ){
Jim_SetResult_sprintf( goi->interp,
"not a number: %s",
Jim_GetString( o, NULL ) );
}
}
return r;
}
int
Jim_GetOpt_Wide( Jim_GetOptInfo *goi, jim_wide *puthere )
{
int r;
Jim_Obj *o;
jim_wide _safe;
if( puthere == NULL ){
puthere = &_safe;
}
r = Jim_GetOpt_Obj( goi, &o );
if( r == JIM_OK ){
r = Jim_GetWide( goi->interp, o, puthere );
}
return r;
}
int Jim_GetOpt_Nvp( Jim_GetOptInfo *goi,
const Jim_Nvp *nvp,
Jim_Nvp **puthere)
{
Jim_Nvp *_safe;
Jim_Obj *o;
int e;
if( puthere == NULL ){
puthere = &_safe;
}
e = Jim_GetOpt_Obj( goi, &o );
if( e == JIM_OK ){
e = Jim_Nvp_name2value_obj( goi->interp,
nvp,
o,
puthere );
}
return e;
}
void
Jim_GetOpt_NvpUnknown( Jim_GetOptInfo *goi,
const Jim_Nvp *nvptable,
int hadprefix )
{
if( hadprefix ){
Jim_SetResult_NvpUnknown( goi->interp,
goi->argv[-2],
goi->argv[-1],
nvptable );
} else {
Jim_SetResult_NvpUnknown( goi->interp,
NULL,
goi->argv[-1],
nvptable );
}
}
int
Jim_GetOpt_Enum( Jim_GetOptInfo *goi,
const char * const * lookup,
int *puthere)
{
int _safe;
Jim_Obj *o;
int e;
if( puthere == NULL ){
puthere = &_safe;
}
e = Jim_GetOpt_Obj( goi, &o );
if( e == JIM_OK ){
e = Jim_GetEnum( goi->interp,
o,
lookup,
puthere,
"option",
JIM_ERRMSG );
}
return e;
}
int
Jim_SetResult_sprintf( Jim_Interp *interp, const char *fmt,... )
{
va_list ap;
#if 0
/* yucky way */
char buf[2048];
va_start(ap,fmt);
vsnprintf( buf, sizeof(buf), fmt, ap );
va_end(ap);
/* garentee termination */
buf[2047] = 0;
Jim_SetResultString( interp, buf, -1 );
#else
char *buf;
va_start(ap,fmt);
vasprintf( &buf, fmt, ap );
va_end(ap);
if( buf ){
Jim_SetResultString( interp, buf, -1 );
free(buf);
}
#endif
return JIM_OK;
}
void
Jim_SetResult_NvpUnknown( Jim_Interp *interp,
Jim_Obj *param_name,
Jim_Obj *param_value,
const Jim_Nvp *nvp )
{
if( param_name ){
Jim_SetResult_sprintf( interp,
"%s: Unknown: %s, try one of: ",
Jim_GetString( param_name, NULL ),
Jim_GetString( param_value, NULL ) );
} else {
Jim_SetResult_sprintf( interp,
"Unknown param: %s, try one of: ",
Jim_GetString( param_value, NULL ) );
}
while( nvp->name ){
const char *a;
const char *b;
if( (nvp+1)->name ){
a = nvp->name;
b = ", ";
} else {
a = "or ";
b = nvp->name;
}
Jim_AppendStrings( interp,
Jim_GetResult(interp),
a, b, NULL );
nvp++;
}
}
static Jim_Obj *debug_string_obj;
const char *
Jim_Debug_ArgvString( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
{
int x;
if( debug_string_obj ){
Jim_FreeObj( interp, debug_string_obj );
}
debug_string_obj = Jim_NewEmptyStringObj( interp );
for( x = 0 ; x < argc ; x++ ){
Jim_AppendStrings( interp,
debug_string_obj,
Jim_GetString( argv[x], NULL ),
" ",
NULL );
}
return Jim_GetString( debug_string_obj, NULL );
}
/*
* Local Variables: ***
* c-basic-offset: 4 ***
* tab-width: 4 ***
* End: ***
*/
......@@ -37,6 +37,31 @@
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the Jim Tcl Project.
*
*--- Inline Header File Documentation ---
* [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
*
* Belief is "Jim" would greatly benifit if Jim Internals where
* documented in some way - form whatever, and perhaps - the package:
* 'doxygen' is the correct approach to do that.
*
* Details, see: http://www.stack.nl/~dimitri/doxygen/
*
* To that end please follow these guide lines:
*
* (A) Document the PUBLIC api in the .H file.
*
* (B) Document JIM Internals, in the .C file.
*
* (C) Remember JIM is embedded in other packages, to that end do
* not assume that your way of documenting is the right way, Jim's
* public documentation should be agnostic, such that it is some
* what agreeable with the "package" that is embedding JIM inside
* of it's own doxygen documentation.
*
* (D) Use minimal Doxygen tags.
*
* This will be an "ongoing work in progress" for some time.
**/
#ifndef __JIM__H
......@@ -557,6 +582,47 @@ typedef struct Jim_Reference {
char tag[JIM_REFERENCE_TAGLEN+1];
} Jim_Reference;
/** Name Value Pairs, aka: NVP
* - Given a string - return the associated int.
* - Given a number - return the associated string.
* .
*
* Very useful when the number is not a simple index into an array of
* known string, or there may be multiple strings (aliases) that mean then same
* thing.
*
* An NVP Table is terminated with ".name=NULL".
*
* During the 'name2value' operation, if no matching string is found
* the pointer to the terminal element (with p->name==NULL) is returned.
*
* Example:
* \code
* const Jim_Nvp yn[] = {
* { "yes", 1 },
* { "no" , 0 },
* { "yep", 1 },
* { "nope", 0 },
* { NULL, -1 },
* };
*
* Jim_Nvp *result
* e = Jim_Nvp_name2value( interp, yn, "y", &result );
* returns &yn[0];
* e = Jim_Nvp_name2value( interp, yn, "n", &result );
* returns &yn[1];
* e = Jim_Nvp_name2value( interp, yn, "Blah", &result );
* returns &yn[4];
* \endcode
*
* During the number2name operation, the first matching value is returned.
*/
typedef struct {
const char *name;
int value;
} Jim_Nvp;
/* -----------------------------------------------------------------------------
* Exported API prototypes.
* ---------------------------------------------------------------------------*/
......@@ -577,6 +643,10 @@ typedef struct Jim_Reference {
/* Macros are common for core and extensions */
#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
#ifdef DOXYGEN
#define JIM_STATIC
#define JIM_API( X ) X
#else
#ifndef __JIM_CORE__
# if defined JIM_EXTENSION || defined JIM_EMBEDDED
# define JIM_API(x) (*x)
......@@ -593,6 +663,10 @@ typedef struct Jim_Reference {
# define JIM_STATIC static
# endif
#endif /* __JIM_CORE__ */
#endif /* DOXYGEN */
/** Set the result - printf() style */
JIM_STATIC int JIM_API( Jim_SetResult_sprintf )( Jim_Interp *p, const char *fmt, ... );
/* Memory allocation */
JIM_STATIC void * JIM_API(Jim_Alloc) (int size);
......@@ -790,6 +864,7 @@ JIM_STATIC int JIM_API(Jim_GetLong) (Jim_Interp *interp, Jim_Obj *objPtr,
long *longPtr);
JIM_STATIC void JIM_API(Jim_SetWide) (Jim_Interp *interp, Jim_Obj *objPtr,
jim_wide wideValue);
#define Jim_NewWideObj Jim_NewIntObj
JIM_STATIC Jim_Obj * JIM_API(Jim_NewIntObj) (Jim_Interp *interp,
jim_wide wideValue);
......@@ -810,7 +885,11 @@ JIM_STATIC void JIM_API(Jim_ReleaseSharedString) (Jim_Interp *interp,
JIM_STATIC void JIM_API(Jim_WrongNumArgs) (Jim_Interp *interp, int argc,
Jim_Obj *const *argv, const char *msg);
JIM_STATIC int JIM_API(Jim_GetEnum) (Jim_Interp *interp, Jim_Obj *objPtr,
const char **tablePtr, int *indexPtr, const char *name, int flags);
const char * const *tablePtr, int *indexPtr, const char *name, int flags);
JIM_STATIC int JIM_API(Jim_GetNvp) (Jim_Interp *interp,
Jim_Obj *objPtr,
const Jim_Nvp *nvp_table,
const Jim_Nvp **result);
JIM_STATIC int JIM_API(Jim_ScriptIsComplete) (const char *s, int len,
char *stateCharPtr);
......@@ -850,6 +929,228 @@ JIM_STATIC size_t JIM_API( Jim_fread )( Jim_Interp *interp, void *ptr, size_
JIM_STATIC int JIM_API( Jim_fflush )( Jim_Interp *interp, void *cookie );
JIM_STATIC char * JIM_API( Jim_fgets )( Jim_Interp *interp, char *s, int size, void *cookie );
/* Name Value Pairs Operations */
JIM_STATIC Jim_Nvp *JIM_API(Jim_Nvp_name2value_simple)( const Jim_Nvp *nvp_table, const char *name );
JIM_STATIC Jim_Nvp *JIM_API(Jim_Nvp_name2value_nocase_simple)( const Jim_Nvp *nvp_table, const char *name );
JIM_STATIC Jim_Nvp *JIM_API(Jim_Nvp_value2name_simple)( const Jim_Nvp *nvp_table, int v );
JIM_STATIC int JIM_API(Jim_Nvp_name2value)( Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result );
JIM_STATIC int JIM_API(Jim_Nvp_name2value_nocase)( Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result);
JIM_STATIC int JIM_API(Jim_Nvp_value2name)( Jim_Interp *interp, const Jim_Nvp *nvp_table, int value, Jim_Nvp **result );
JIM_STATIC int JIM_API(Jim_Nvp_name2value_obj)( Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result );
JIM_STATIC int JIM_API(Jim_Nvp_name2value_obj_nocase)( Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result );
JIM_STATIC int JIM_API(Jim_Nvp_value2name_obj)( Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *value_obj, Jim_Nvp **result );
/** prints a nice 'unknown' parameter error message to the 'result' */
JIM_STATIC void JIM_API(Jim_SetResult_NvpUnknown)( Jim_Interp *interp,
Jim_Obj *param_name,
Jim_Obj *param_value,
const Jim_Nvp *nvp_table );
/** Debug: convert argc/argv into a printable string for printf() debug
*
* \param interp - the interpeter
* \param argc - arg count
* \param argv - the objects
*
* \returns string pointer holding the text.
*
* Note, next call to this function will free the old (last) string.
*
* For example might want do this:
* \code
* fp = fopen("some.file.log", "a" );
* fprintf( fp, "PARAMS are: %s\n", Jim_DebugArgvString( interp, argc, argv ) );
* fclose(fp);
* \endcode
*/
JIM_STATIC const char *JIM_API( Jim_Debug_ArgvString )( Jim_Interp *interp, int argc, Jim_Obj *const *argv );
/** A TCL -ish GetOpt like code.
*
* Some TCL objects have various "configuration" values.