This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Call Function By Name
  Submitted by



This code illustrates how one can call a function using a string literal, or a char * this makes it very useful for in-game command consoles, or scripting languages, or whatever you want. All you have to do to call the function is

CallFunctionByName("MyFunction", args); or strcpy(funcCaller, "MyFunction");
CallFunctionByName(funcCaller, args); (For the reference: This code uses a modified version of John W. Ratcliff's StringTable class - Thanks John!) Happy Coding

Currently browsing [CallFunc.zip] (32,369 bytes) - [test.cpp] - (2,484 bytes)

/* File:		test.cpp
 * Author(s):	Michael Deardeuff	<mr__goodbytes@hotmail.com
 * Description:
 *		Tests the CallFunctionByName Routine
 * Notes:
 *		Copyright (C) 2000 Michael Deardeuff
 *		You may use this code in anything you want as long as you keep the copyright notices intact
 */

#ifdef _MSC_VER // >= 1200 // For MSVC++ Only (6.0+ in comments) #pragma warning(disable :4786) // Disable all those pesky warnings you get #endif // _MSC_VER // from using the STL #include <map>

#include "mgTable.h" #include "function.h" /* extern "C" { StringTable functionTable; std::map<char *, FunctionPointer> mFunction; } */ void FunctionTableInit();

int main() { FunctionTableInit();

bool done=false; char buf[32]; do { printf("Enter name of function in function table\n"); printf("Or enter 'bye', 'quit', or 'end' to exit:\n"); printf("Currently only HoserChild and MrGoodbytes\n"); printf("are valid function names\n\nFunction: "); // Get Function name if( fgets( buf, sizeof( buf ), stdin ) == NULL ) { done = true; break; } // remove the trailing '\n' from string strchr(buf, 10)[0] = '\0'; // isn't that ugly :C String command = buf; // see if user wants to quit if ( command == "bye" || command == "end" || command == "quit" ) { done = true; break; } else { // enter "arguments" printf("\nEnter a string to pass as an argument\nArgs: ");

command = buf; if( fgets( buf, sizeof( buf ), stdin ) == NULL ) { done = true; break; } printf("\n\n-------------------------------------------\n\n"); if (!CallFunctionByName((char *)command.c_str(), buf)) printf("\n%s is not in the Callable Function Table\n\n", command.c_str()); } } while ( !done );

printf("\n\n---------------------------------\n\n"); // Can also be called with a string literal: CallFunctionByName( "MrGoodbytes", (void *)"Goodbye");

return 0; }

// Add the functions to the list void FunctionTableInit() { AddFunction("HoserChild", HoserChild); AddFunction("MrGoodbytes", MrGoodbytes); AddFunction("NullFunc", NULL); };

/**** The User Callable Functions ********************************************/ void HoserChild(void *args) { printf("HoserChild says:\n%s\n", (char *)args); }

void MrGoodbytes(void *args) { printf("Mr Goodbytes' own personal function:\n%s\n", (char *)args); }

Currently browsing [CallFunc.zip] (32,369 bytes) - [CallFunc.cpp] - (2,967 bytes)

/* File:		CallFunc.cpp
 * Author(s):	Michael Deardeuff <mr__goodbytes@hotmail.com>
 * Description:
 *		Implements CallFunctionByName() and AddFunction() methods
 * Notes:
 *		Copyright (C) 2000 Michael Deardeuff
 *		You may use the code in whatever you want as long as the copyright notice stays intact.
 * Usage:
 *		To use these to functions(methods if you prefer), you first add the function to the
 *		"Callable Function List" by calling AddFunction() with the name you wish to give the
 *		function, and the function itself. Then to call the function in your code, you invoke
 *		CallFunctionByName() with the name you gave the function, and any arguments you may wish.
 *		to pass to the function.
 *		Example:
 *
 *			void CallMeFunc(void *args)
 *			{
 *				// Do Something...
 *			}
 *
 *			int main()
 *			{
 *				char funcCaller = "MyFunction";	// for later
 *				
 *				// Add the Function to the "Callable Function List"
 *				AddFunction("MyFunction", CallMeFunc);
 *				
 *				// Call the function in a variaty of ways
 *				CallFunctionByName("MyFunction", NULL);
 *				CallFunctionByName(funcCaller, NULL);
 *
 *				// ...
 *				return 0;
 *			}
 *		
 *		I find this useful when using a scripting language, or a console debugger in your game.
 *		Happy Coding!
 *		-Michael Deardeuff
 */

#ifdef _MSC_VER // >= 1200 // For MSVC++ Only (6.0+ in comments) #pragma warning(disable :4786) // Disable all those pesky warnings you get #endif // _MSC_VER // from using the STL #include <map>

#include "mgTable.h" #include "function.h"

// For use by our "map" class FunctionPointer { public: void (*pFunc)(void *args); };

StringTable functionTable; std::map<char *, FunctionPointer> mFunction;

/* CallFunctionByName(): * Calls a function associated with to a string name * Functions must be added to callable list via AddFunctions() */ bool CallFunctionByName (char * pName, void * args) { char * result;

// If the name is in the list, call it; if (functionTable.IsIn(pName)) { result = (char*)functionTable.Get(pName); mFunction[ result ].pFunc( args ); // this is a good thing about maps return true; //Ok } return false; // Didn't happen }

/* AddFunction(): * Adds functions and their associated strings to the list * callable by CallFunctionName * returns true if successful */ bool AddFunction(char * pName, void (*pFunc)(void *args)) { FunctionPointer fp; char * result;

// Test to see whether pFunc is valid, and whether // pName is already listed in the set if ((pFunc != NULL) && (functionTable.IsIn(pName))) return false; // Already something with that name in list // Puts name in the function table result = (char *) functionTable.Get(pName); // Assign the function pointer to the map // with the above result as the key fp.pFunc = pFunc; mFunction[result] = fp; return true; // Ok }

Currently browsing [CallFunc.zip] (32,369 bytes) - [function.h] - (520 bytes)

#ifndef FUNCTION_H
#define FUNCTION_H

#ifdef _MSC_VER // >= 1200 // For MSVC++ Only (6.0+ in comments) #pragma warning(disable :4786) // Disable all those pesky warnings you get #endif // _MSC_VER // from using the STL // Defines (or includes) all callable functions for use of Call...ByName()

bool CallFunctionByName (char * pName, void* args); bool AddFunction(char *pName, void (*pFunc)(void *args));

void HoserChild(void *args); void MrGoodbytes(void *args);

#endif // FUNCTION_H

Currently browsing [CallFunc.zip] (32,369 bytes) - [mgTable.cpp] - (2,172 bytes)

/* File:		mgTable.cpp
 * Author(s):	John W. Ratcliff	<jratcliff@verant.com>
 *				Michael Deardeuff	<mr__goodbytes@hotmail.com>
 * Descripton:
 *		Implements the StringTable class. For a better description, consult "sTable.h"
 * Notes:
 *		John W. Ratcliff made about 99% of this. All thanks go to him
 *		Michael Deardeuff just added IsIn() for use of CallFunctionByName
 */

#ifdef _MSC_VER // >= 1200 // For MSVC++ Only (6.0+ in comments) #pragma warning(disable :4786) // Disable all those pesky warnings you get #endif // _MSC_VER // from using the STL #include <string.h> #include <string> #include <set> #include "mgTable.h"

// Compares two strings, returns true if first is less than second (used by std::set) bool CharPtrLess::operator()(const char *v1,const char *v2) const { int v = strcmp(v1,v2); if ( v < 0 ) return true; return false; }

// Clean up. StringTable::~StringTable(void) { CharPtrSet::iterator i; for (i=mStrings.begin(); i!=mStrings.end(); i++) { char *str = (char *)(*i); delete str; } }

/* Get(): * Searches the set, seeing if "str" is already in set. * If so, returns a pointer to the string, If not, * creates a new string, and returns a pointer to * the newly allocated string; */ const char * StringTable::Get(const char *str) { CharPtrSet::iterator found;

// Search the set for str found = mStrings.find( str );

// if found return pointer to the original string if ( found != mStrings.end() ) return (*found);

// create a new string identical to "str" int lngth = strlen(str); char *mem = new char[lngth+1]; strcpy(mem,str); // insert new string into the set, and return a pointer mStrings.insert( mem ); return mem; }

/* IsIn(): * Searches the set for occurance of "str". Returns True * if found, false if not */ bool StringTable::IsIn(const char *str) { CharPtrSet::iterator found; found = mStrings.find( str ); if (found != mStrings.end()) return true; return false; }

const char * StringTable::Get(const String &str) { return Get( str.c_str() ); }

Currently browsing [CallFunc.zip] (32,369 bytes) - [mgTable.h] - (4,189 bytes)

#ifndef MR_GOODBYTES_TABLE_H
#define MR_GOODBYTES_TABLE_H

#ifdef _MSC_VER // >= 1200 // For MSVC++ Only (6.0+ in comments) #pragma warning(disable :4786) // Disable all those pesky warnings you get #endif // _MSC_VER // from using the STL #include <string.h> #include <string> #include <set>

// This class implements a 'stringtable'. It is being released into // the public domain on September 27, 2000 by John W. Ratcliff // jratcliff@verant.com for FlipCode.com as part of the 'code of they day' // project. // // What the heck does a 'StringTable' class do for me? What a StringTable // is used for is to manage a collection of shared strings across a package. // It is primarily used for tokens, keywords, asset names, etc. You do // *NOT* want to use the StringTable for any cases which could produce // an infinite number of strings. This is only for managing a finite list // of keywords. // // The reason you use a string table is so that you can keep track of items // by ASCII name instead of some non-intutitive and arbritrary id number. // Normally it is not practical to make a container class who's key is // an STL string. First of all there is a memory overhead, and additionally // there is a serious peformance penalty. However, with the StringTable // class, instead you can keep track of a list of items where the key is // a pointer to the string, instead of the string itself. Now you can // compare if 'two strings are equal' simply by comparing if their address // is the same. Remember that any container class which uses this pointer as // a key is *NOT* in alphabetical order!! It's ordered based on the address // in memory of the string itself. But that doesn't matter, because the // purpose of the container is not to maintain an alphabetical list of // items but rather to simply locate items *BY NAME* extremely quickly. // // Using a stringtable makes it trivial to keep ASCII names and descriptions // as member variables in all of your classes. This makes debugging and // debug output vastly simpler. // // Example: Say you contruct a new intance of a Vehicle class. In it's // constructor you might have something like: // // mObjectName = gStringTable.Get("vehicle"); // // Where mObjectName is a member variable of type 'const char *' and // gStringTable is some global instance of a shared string table across // your application. Now, you can compare whether or not an object is of // type 'vehicle' simply by comparing it's name to anybody else's name // with the two pointers allocated with the same string table. // // This is extremely convenient for debugging, logging, etc. // // To create an STL map where you access every item *by name* all you // have to do is: // // typedef std::map< const char * , Texture *> TextureMap; // // This would create an STL map that would allow you to quickly look // up any texture by name. A fairly useful data structure. // // Example of how to locate a texture by name: // // **NOTE* texname must have been created by the same StringTable // // Texture * FindTexture(const char *texname) // { // TextureMap::iterator found; // STL map iterator to find item. // found = mTextures.find( texname ); // search red/black tree // if ( found != mTextures.end() ) return (*found).second; // return 0; // no texture of this name found. // } // // The string table implementation uses STL to maintain the collection // of strings. If you change the comparator function in CharPtrLess // from strcmp to stricmp then all of your strings will be created without // case sensitivity, which is often the behavior you want for tokens and // keywords. typedef std::string String;

class CharPtrLess { public: bool operator()(const char *v1,const char *v2) const; };

typedef std::set< const char *, CharPtrLess > CharPtrSet;

class StringTable { public: StringTable(void){}

~StringTable(void); const char * Get(const char *str); const char * Get(const String &str);

bool IsIn(const char *str); private: CharPtrSet mStrings; };



#endif //MR_GOODBYTES_TABLE_H

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.