#ifdef _WIN32
#include <io.h>
#define access _access
#else
#include <unistd.h>
#endif
#include <fcntl.h>
#include <stdlib.h>

#include <cdevDirectory.h>
#include <cdevDirectoryTool.h>
#include <cdevDirectoryTable.h>
#include <cdevDirRequestObj.h>

// *****************************************************************************
// * compressMessage :
// *	This function is designed to walk through a message string
// * 	and remove any extraneous spaces or tabs.
// *****************************************************************************
static void compressMessage ( char * string )
	{
	if(string!=NULL)
		{
		while(*string)
			{
			if(isspace(*string))
				{
				for(char *ptr=string; isspace(*ptr); ptr++);
				if(*ptr==0) *string=0;
				else if(ptr>string+1)
					{
					*(string++)=' ';
					strcpy(string, ptr);
					}
				else string++;
				}
			else string++;
			}
		}
	}


// *****************************************************************************
// * compressMessage :
// *	This function is designed to walk through a message string specified
// * 	within a cdevData object and remove any extraneous spaces or tabs.
// *****************************************************************************
static void compressMessage( cdevData * data )
	{
	static int MESSAGE_TAG = 0;	

	// *********************************************************************
	// * If the data points to an actual cdevData object and the message
	// * tag has been defined, then extract the message from the cdevData 
	// * object and remove any spaces that it might contain.
	// * 
	// * Note that I am using the integer cdevData tags in order to reduce
	// * the time required to extract and manipulate the message.
	// *********************************************************************
	if(data && (MESSAGE_TAG || !cdevData::tagC2I("message", &MESSAGE_TAG)))
		{
		char * ptr = NULL;
		data->find(MESSAGE_TAG, (void *&)ptr);
		if(ptr && *ptr) compressMessage(ptr);
		}
	}



// *****************************************************************************
// * cdevDirectory::cdevDirectory :
// *	This is the constructor for a cdevDirectory object.
// *****************************************************************************
cdevDirectory::cdevDirectory(cdevSystem &system)
	: cdevDevice("cdevDirectory", system),
	  node       (NULL),
	  table      (new cdevDirectoryTable()),
	  commandHash(new StringHash)
	{
	char *filename=::getenv("CDEVDDL");
	char extFilename[512];
	
	// *********************************************************************
	// * Populate the cdevDirectory using the CDEVDDL environment variable.
	// *********************************************************************
	if(filename)
		{
		sprintf(extFilename, "%s-%s.%s", filename, 
			cdevSystem::CDEV_MAJOR_VERSION, 
			cdevSystem::CDEV_MINOR_VERSION);
		
		if(!access(extFilename, 00))   table->load(extFilename);
		else if(!access(filename, 00)) table->load(filename);
		}

	// *********************************************************************
	// * Create the hash table of commands.
	// *********************************************************************
	commandHash->insert("query", 
			    (void *)&(cdevDirectory::query));
	commandHash->insert("queryClass", 
			    (void *)&(cdevDirectory::queryClass));
	commandHash->insert("queryClasses", 
			    (void *)&(cdevDirectory::queryClasses));
	commandHash->insert("queryCollection",
			    (void *)&(cdevDirectory::queryCollection));
	commandHash->insert("queryVerbs", 
			    (void *)&(cdevDirectory::queryVerbs));
	commandHash->insert("queryAttributes", 
			    (void *)&(cdevDirectory::queryAttributes));
	commandHash->insert("queryMessages", 
			    (void *)&(cdevDirectory::queryMessages));
	commandHash->insert("service", 
			    (void *)&(cdevDirectory::service));
	commandHash->insert("resolveService", 
			    (void *)&(cdevDirectory::resolveService));
	commandHash->insert("serviceData", 
			    (void *)&(cdevDirectory::serviceData));
	commandHash->insert("resolveServiceData", 
			    (void *)&(cdevDirectory::resolveServiceData));
	commandHash->insert("validate", 
			    (void *)&(cdevDirectory::validate));
	commandHash->insert("update", 
			    (void *)&(cdevDirectory::update));
	commandHash->insert("writeAscii", 
			    (void *)&(cdevDirectory::writeAscii));
	commandHash->insert("writeBinary", 
			    (void *)&(cdevDirectory::writeBinary));
	}

// *****************************************************************************
// * cdevDirectory:~cdevDirectory:
// *	This is the destructor for a cdevDirectory object.
// *****************************************************************************
cdevDirectory::~cdevDirectory(void)
	{
	while(node!=NULL)
		{
		cdevDirectoryNode *curr = node;
		node = curr->next;
		delete curr;
		} 
	delete table;
	delete commandHash;
	}

// *****************************************************************************
// * cdevDirectory::addNameSvc :
// *	This method allows the caller to add a new name service to the list
// *	of name services that are managed by this class.  If the name cannot
// *	be resolved by the cdevDirectory, then each of the name services will
// *	be called until the name has been resolved.
// *****************************************************************************
int
cdevDirectory::addNameSvc(cdevDevice *svc)
	{
	int result = CDEV_SUCCESS;
	
	if(svc)
		{
		int found  = 0;
		cdevDirectoryNode *curr = node, * prev = NULL;
	
		while(curr!=NULL && !found)
			{
			if(curr->device==svc) found = 1;
			prev = curr;
			curr = prev->next;		
			}
		if (!found)
			{
			if(prev) prev->next = new cdevDirectoryNode(svc);
			else     node       = new cdevDirectoryNode(svc);
			}
		else result = CDEV_ERROR;
		}
	else result = CDEV_INVALIDARG;
	
	return result;
	}

// *****************************************************************************
// * cdevDirectory::removeNameSvc :
// *	This method removes a name service from the list that is maintained by 
// *	the cdevDirectory.
// *****************************************************************************
int
cdevDirectory::removeNameSvc(cdevDevice *svc)
	{
	int result = CDEV_SUCCESS;
	
	if(svc)
		{
		int found  = 0;
		cdevDirectoryNode *curr = node, * prev = NULL;
	
		while(curr!=NULL && !found)
			{
			if(curr->device==svc) found = 1;
			else	{
				prev = curr;
				curr = prev->next;		
				}
			}
		if (found)
			{
			if(prev) prev->next = curr->next;
			else     node = curr->next;
			delete curr;
			}
		else result = CDEV_NOTFOUND;
		}
	else result = CDEV_INVALIDARG;
	
	return result;
	}

// *****************************************************************************
// * cdevDirectory::query :
// *	This method calls the query method of the cdevDirectory tool in order
// *	to resolve the request.  If the request cannot be resolved, then each
// *	of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::query ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;

	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::query(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::queryClass :
// *	This method calls the queryClass method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryClass ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;

	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryClass(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::queryClasses :
// *	This method calls the queryClasses method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryClasses ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;

	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryClasses(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::queryCollection :
// *	This method calls the queryCollection method of the cdevDirectoryTool in 
// *	order to obtain the list of devices that are part of a cdevCollection. If 
// *  the request cannot be resolved, then each of the underlying name servers 
// *  objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryCollection ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;

	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryCollection(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}
	
// *****************************************************************************
// * cdevDirectory::queryVerbs :
// *	This method calls the queryVerbs method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryVerbs ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	
	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryVerbs(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::queryAttributes :
// *	This method calls the queryAttributes method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryAttributes ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	
	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryAttributes(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::queryMessages :
// *	This method calls the queryMessages method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::queryMessages ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	
	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::queryMessages(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::service :
// *	This method calls the service method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::service ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	
	if(out==NULL) return CDEV_INVALIDARG;
	
	if((result = cdevDirectoryTool::service(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	// *********************************************************************
	// * If the system includes channel access, then fallthrough to channel
	// * access as the default service.
	// *********************************************************************
	#ifdef _HAS_CA
		if(result!=CDEV_SUCCESS && dir.system_.defaultSvc ())
			{
			char device[255];
			char message[255];

			*device  = 0;
			*message = 0;
			
			if(in)	{
				in->get("device",  device, 255);
				in->get("message", message, 255);
				}
			
			dir.system_.reportError
				(CDEV_SEVERITY_WARN, "CDEV Directory", 0, 
				"No service matches \"%s\" - \"%s\", default to caService",
				device, message);
			
			out->insert("value", "caService");
			result = CDEV_SUCCESS;
			}
	#endif
	return result;
	}

// *****************************************************************************
// * cdevDirectory::resolveService :
// *	This method calls the resolveService method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::resolveService ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	cdevData In;
	
	if(out==NULL) return CDEV_INVALIDARG;
	
	// *********************************************************************
	// * Transfer the name of the device and message to the cdevData In
	// * object for use in the "service" request.
	// *********************************************************************
	if(in) In = *in;
	char *ptr, *tPtr;
	char   device[255];

	// *********************************************************************
	// * Jump over the resolveService command and read the device and 
	// * message.
	// *********************************************************************
	ptr = msg+15;
	while(*ptr &&  isspace(*ptr)) ptr++;
	for(tPtr=device; *ptr && !isspace(*ptr); ) *(tPtr++) = *(ptr++);
	*tPtr = 0;
	while(*ptr && isspace(*ptr)) ptr++;

	// *********************************************************************
	// * Use the compressMessage method to remove any extraneous spaces from
	// * the message string.
	// *********************************************************************
	compressMessage(ptr);

	// *********************************************************************
	// * Place the device and message into the In cdevData object prior to
	// * calling the service method.
	// *********************************************************************
	if(*device) In.insert("device", device);
	if(*ptr)    In.insert("message", ptr);

	if((result = cdevDirectoryTool::service(*dir.table, &In, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}

	// *********************************************************************
	// * If the system includes channel access, then fallthrough to channel
	// * access as the default service.
	// *********************************************************************
	#ifdef _HAS_CA
		if(result!=CDEV_SUCCESS && dir.system_.defaultSvc ())
			{
			dir.system_.reportError
				(CDEV_SEVERITY_WARN, "CDEV Directory", 0, 
				 "No service matches \"%s\" - \"%s\", default to caService",
				 device, ptr);
			
			out->insert("value", "caService");
			result = CDEV_SUCCESS;
			}
	#endif

	return result;
	}

// *****************************************************************************
// * cdevDirectory::serviceData :
// *	This method calls the serviceData method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::serviceData ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;

	if(out==NULL) result = CDEV_INVALIDARG;
	else if((result = cdevDirectoryTool::serviceData(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::resolveServiceData :
// *	This method calls the resolveServiceData method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::resolveServiceData ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	cdevData In;
	
	if(out==NULL) return CDEV_INVALIDARG;
	
	// *********************************************************************
	// * Transfer the name of the device and message to the cdevData In
	// * object for use in the "serviceData" request.
	// *********************************************************************
	if(in) In = *in;
	char *ptr, *tPtr;
	char  device[255];

	// *********************************************************************
	// * Jump over the resolveServiceData command and read the device and 
	// * message.
	// *********************************************************************
	ptr = msg+19;
	while(*ptr &&  isspace(*ptr)) ptr++;
	for(tPtr=device; *ptr && !isspace(*ptr); ) *(tPtr++) = *(ptr++);
	*tPtr = 0;
	while(*ptr && isspace(*ptr)) ptr++;

	// *********************************************************************
	// * Use the compressMessage method to remove any extraneous spaces from
	// * the message string.
	// *********************************************************************
	compressMessage(ptr);
	
	// *********************************************************************
	// * Place the device and message into the In cdevData object prior to
	// * calling the serviceData method.
	// *********************************************************************
	if(*device) In.insert("device", device);
	if(*ptr)    In.insert("message", ptr);

	if((result = cdevDirectoryTool::serviceData(*dir.table, &In, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::validate :
// *	This method calls the validate method of the cdevDirectory tool in 
// *	order to resolve the request.  If the request cannot be resolved, then 
// *	each of the underlying name servers objects will be contacted.
// *****************************************************************************
int 
cdevDirectory::validate ( cdevDirectory &dir, char * msg, cdevData *in, cdevData *out )
	{
	int result = CDEV_SUCCESS;
	if((result = cdevDirectoryTool::validate(*dir.table, in, out))!=CDEV_SUCCESS)
		{
		cdevDirectoryNode * curr = dir.node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::update :
// *	This method calls the update method of the cdevDirectory tool.
// *****************************************************************************
int 
cdevDirectory::update ( cdevDirectory &dir, char *, cdevData *in, cdevData *out )
	{
	return cdevDirectoryTool::update(*dir.table, in, out);
	}

// *****************************************************************************
// * cdevDirectory::writeAscii :
// *	This method calls the writeAscii method of the cdevDirectory tool.
// *****************************************************************************
int 
cdevDirectory::writeAscii ( cdevDirectory &dir, char *, cdevData *in, cdevData *out )
	{
	return cdevDirectoryTool::writeAscii(*dir.table, in, out);
	}

// *****************************************************************************
// * cdevDirectory::writeBinary :
// *	This method calls the writeBinary method of the cdevDirectory tool.
// *****************************************************************************
int 
cdevDirectory::writeBinary ( cdevDirectory &dir, char *, cdevData *in, cdevData *out )
	{
	return cdevDirectoryTool::writeBinary(*dir.table, in, out);
	}

// *****************************************************************************
// * cdevDirectory::send :
// *	This method performs a synchronous send.
// *****************************************************************************
int
cdevDirectory::send(char *msg, cdevData &in, cdevData &out)
	{
	return send(msg, &in, &out);
	}

// *****************************************************************************
// * cdevDirectory::send :
// *	This method performs a synchronous send.
// *****************************************************************************
int
cdevDirectory::send(char *msg, cdevData &in, cdevData *out)
	{
	return send(msg, &in, out);
	}

// *****************************************************************************
// * cdevDirectory::send :
// *	This method performs a synchronous send.
// *****************************************************************************
int
cdevDirectory::send(char *msg, cdevData *in, cdevData &out)
	{
	return send(msg, in, &out);
	}

// *****************************************************************************
// * cdevDirectory::send :
// *	This method performs a synchronous send.
// *****************************************************************************
int
cdevDirectory::send(char *msg, cdevData *in, cdevData *out)
	{
	enum { MAX_VERB_LEN = 255 };
	static char verb[MAX_VERB_LEN];

	int           verbIdx = 0;
	int	      result  = CDEV_SUCCESS;
	char	     *msgPtr  = msg;
	QueryFunction func    = NULL;

	// *********************************************************************
	// * Extract the verb portion of the message.
	// *********************************************************************
	while(*msgPtr && !isspace(*msgPtr) && verbIdx<MAX_VERB_LEN) 
		{
		verb[verbIdx++] = *(msgPtr++);
		}
	verb[verbIdx] = 0;

	// *********************************************************************
	// * Use the verb to locate the specific command function.
	// *********************************************************************
	func = (QueryFunction)commandHash->find(verb);
	
	// *********************************************************************
	// * Use the compressMessage method to remove any extraneous spaces
	// * from the message string (if it exists).
	// *********************************************************************
	compressMessage(in);

	// *********************************************************************
	// * Execute the function if it is available, otherwise, descend through
	// * the list of register name services and allow each of them to have
	// * a crack at it.
	// *********************************************************************
	if(func!=NULL) result = (*func)(*this, msg, in, out);
	else	{
		cdevDirectoryNode * curr = node;
		while(curr!=NULL && (result=curr->device->send(msg, in, out))!=CDEV_SUCCESS)
			{
			curr = curr->next;
			}
		}
	return result;
	}

// *****************************************************************************
// * cdevDirectory::sendNoBlock :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendNoBlock(char *msg, cdevData &in, cdevData &out)
	{
	return send(msg, in, out);
	}

// *****************************************************************************
// * cdevDirectory::sendNoBlock :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendNoBlock(char *msg, cdevData *in, cdevData &out)
	{
	return send(msg, in, out);
	}

// *****************************************************************************
// * cdevDirectory::sendNoBlock :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendNoBlock(char *msg, cdevData &in, cdevData *out)
	{
        return send(msg, in, out);
	}


// *****************************************************************************
// * cdevDirectory::sendNoBlock :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendNoBlock(char *msg, cdevData *in, cdevData *out)
	{
        return send(msg, in, out);
	}

// *****************************************************************************
// * cdevDirectory::sendCallback :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendCallback(char *msg, cdevData &in, cdevCallback &cb)
	{
	cdevData            out;
	int                 result;
	cdevRequestObject & reqObj = *cdevSystem::defaultSystem().errorRequestObject();
	
	result = send(msg, &in, &out);
	cb.fireCallback(result, cb.userarg(), reqObj, out, 0);
	return result;
	}

// *****************************************************************************
// * cdevDirectory::sendCallback :
// *	This method performs an asynchronous send.
// *****************************************************************************
int
cdevDirectory::sendCallback(char *msg, cdevData *in, cdevCallback &cb)
	{
	cdevData            out;
	int                 result;
	cdevRequestObject & reqObj = *cdevSystem::defaultSystem().errorRequestObject();

	result = send(msg, in, &out);
	if (result == CDEV_SUCCESS) 
	  cb.fireCallback(result, cb.userarg(), reqObj, out, 0);
	return result;
	}


// *****************************************************************************
// * cdevDirectory::getRequestObject :
// *	Allows the caller to obtain a request object for the specified message.
// *****************************************************************************
cdevRequestObject *cdevDirectory::getRequestObject(char *msg)
	{
	cdevRequestObject *obj=NULL;
	getRequestObject(msg, obj);
	return obj;
	}

// *****************************************************************************
// * cdevDirectory::getRequestObject :
// *	Allows the caller to obtain a request object for the specified message.
// *****************************************************************************
int
cdevDirectory::getRequestObject(char* msg, cdevRequestObject* &reqobj)
	{
	if (reqobj = findRequestObject (msg)) {
#ifdef _CDEV_DEBUG
	  printf ("cdevDirectory: Find request object for %s\n", msg);
#endif
	  reqobj->ref ();
	  return CDEV_SUCCESS;
	  }
#ifdef _CDEV_DEBUG
	printf ("cdevDirectory: create new request object for %s\n", msg);
#endif
	reqobj = new cdevDirRequestObj (*this, msg, system_);
	if (reqobj) {
	  registerReqObject (reqobj);
	  return CDEV_SUCCESS;
	  }
	return CDEV_ERROR;
        }

