Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/shell/shell_command.cc @ 5641

Last change on this file since 5641 was 5641, checked in by bensch, 19 years ago

orxonox/trunk: Passing Reference inastead of Pointer to create ShellCommand

File size: 12.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell_command.h"
19#include "shell_command_class.h"
20
21#include "list.h"
22#include "debug.h"
23#include "class_list.h"
24
25#include "key_names.h"
26#include <stdarg.h>
27#include <stdio.h>
28#include <string.h>
29
30using namespace std;
31
32/**
33 * constructs and registers a new Command
34 * @param commandName the name of the Command
35 * @param className the name of the class to apply this command to
36 * @param paramCount the count of parameters this command takes
37 */
38ShellCommand::ShellCommand(const char* commandName, const char* className, const Executor& executor)
39{
40  this->setClassID(CL_SHELL_COMMAND, "ShellCommand");
41  this->setName(commandName);
42  this->description = NULL;
43  this->alias = NULL;
44
45//  this->classID = classID;
46  this->shellClass = ShellCommandClass::getCommandClass(className); //ClassList::IDToString(classID);
47  if (this->shellClass != NULL)
48    this->shellClass->commandList->add(this);
49  // handling parameters, and storing them:
50  if (paramCount > FUNCTOR_MAX_ARGUMENTS)
51    paramCount = FUNCTOR_MAX_ARGUMENTS;
52  this->paramCount = paramCount;
53  this->parameters = new unsigned int[paramCount];
54  this->defaultValue = new MultiType[paramCount];
55
56  this->executor = executor.clone();
57}
58
59/**
60 * deconstructs a ShellCommand
61 */
62ShellCommand::~ShellCommand()
63{
64  delete[] this->parameters;
65  delete[] this->defaultValue;
66  if (this->alias != NULL && ShellCommandClass::aliasList != NULL)
67  {
68    ShellCommandClass::aliasList->remove(this->alias);
69    delete this->alias;
70  }
71  delete this->executor;
72}
73
74/**
75 * registers a new ShellCommand
76 */
77ShellCommand* ShellCommand::registerCommand(const char* commandName, const char* className, const Executor& executor)
78{
79  if (ShellCommand::isRegistered(commandName, className, executor))
80    return NULL;
81  else
82    return new ShellCommand(commandName, className, executor);
83
84}
85
86
87
88
89/**
90 * unregister an existing commandName
91 * @param className the name of the Class the command belongs to.
92 * @param commandName the name of the command itself
93 */
94void ShellCommand::unregisterCommand(const char* commandName, const char* className)
95{
96  if (ShellCommandClass::commandClassList == NULL)
97    ShellCommandClass::initCommandClassList();
98
99 const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
100
101 if (checkClass != NULL)
102  {
103    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
104    ShellCommand* elem = iterator->firstElement();
105    while(elem != NULL)
106    {
107      if (!strcmp(commandName, elem->getName()))
108      {
109        checkClass->commandList->remove(elem);
110        delete elem;
111        break;
112      }
113      elem = iterator->nextElement();
114    }
115    delete iterator;
116
117    if (checkClass->commandList->getSize() == 0)
118    {
119      ShellCommandClass::commandClassList->remove(checkClass);
120      delete checkClass;
121    }
122  }
123}
124
125/**
126 * checks if a command has already been registered.
127 * @param commandName the name of the Command
128 * @param className the name of the Class the command should apply to.
129 * @param paramCount how many arguments the Command takes
130 * @returns true, if the command is registered/false otherwise
131 *
132 * This is used internally, to see, if we have multiple command subscriptions.
133 * This is checked in the registerCommand-function.
134 */
135bool ShellCommand::isRegistered(const char* commandName, const char* className, const Executor& executor)
136{
137  if (ShellCommandClass::commandClassList == NULL)
138  {
139    ShellCommandClass::initCommandClassList();
140    return false;
141  }
142
143  const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
144  if (checkClass != NULL)
145  {
146    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
147    ShellCommand* elem = iterator->firstElement();
148    while(elem != NULL)
149   {
150     if (!strcmp(commandName, elem->getName()))
151     {
152       PRINTF(2)("Command already registered\n");
153       delete iterator;
154       return true;
155      }
156     elem = iterator->nextElement();
157   }
158   delete iterator;
159   return false;
160  }
161  else
162    return false;
163}
164
165
166/**
167 * executes commands
168 * @param executionString the string containing the following input
169 * ClassName [ObjectName] functionName [parameter1[,parameter2[,...]]]
170 * @return true on success, false otherwise.
171 */
172bool ShellCommand::execute(const char* executionString)
173{
174  if (ShellCommandClass::commandClassList == NULL)
175    return false;
176
177  long classID = CL_NULL;                 //< the classID retrieved from the Class.
178  ShellCommandClass* commandClass = NULL; //< the command class this command applies to.
179  tList<BaseObject>* objectList = NULL;   //< the list of Objects stored in classID
180  BaseObject* objectPointer = NULL;       //< a pointer to th Object to Execute the command on
181  bool emptyComplete = false;             //< if the completion input is empty string. e.g ""
182  unsigned int fktPos = 1;                //< the position of the function (needed for finding it)
183//  long completeType = SHELLC_NONE;      //< the Type we'd like to complete.
184  SubString inputSplits(executionString, true);
185
186  if (inputSplits.getCount() == 0)
187    return false;
188  if (inputSplits.getCount() >= 1)
189  {
190    // CHECK FOR ALIAS
191    if (ShellCommandClass::aliasList != NULL)
192    {
193      tIterator<ShellCommandAlias>* itAL = ShellCommandClass::aliasList->getIterator();
194      ShellCommandAlias* elemAL = itAL->firstElement();
195      while(elemAL != NULL)
196      {
197        if (elemAL->getName() != NULL && !strcmp(elemAL->getName(), inputSplits.getString(0)) && elemAL->getCommand() != NULL &&
198            elemAL->getCommand()->shellClass != NULL )
199        {
200          objectList = ClassList::getList(elemAL->getCommand()->shellClass->getName());
201          if (objectList != NULL)
202          {
203            if (inputSplits.getCount() > 1)
204              elemAL->getCommand()->executor->execute(objectList->firstElement(), executionString+inputSplits.getOffset(1));
205            else
206              elemAL->getCommand()->executor->execute(objectList->firstElement(), "");
207            delete itAL;
208            return true;
209          }
210        }
211        elemAL = itAL->nextElement();
212      }
213      delete itAL;
214    }
215    // looking for a Matching Class
216    if (likely(ShellCommandClass::commandClassList != NULL))
217    {
218      tIterator<ShellCommandClass>* itCL = ShellCommandClass::commandClassList->getIterator();
219      ShellCommandClass* elemCL = itCL->firstElement();
220      while(elemCL != NULL)
221      {
222        if (elemCL->getName() && !strcasecmp(inputSplits.getString(0), elemCL->getName()))
223        {
224          //elemCL->getName();
225          classID = ClassList::StringToID(elemCL->getName());
226          commandClass = elemCL;
227          objectList = ClassList::getList(classID);
228          break;
229        }
230        elemCL = itCL->nextElement();
231      }
232      delete itCL;
233    }
234
235    if (commandClass != NULL && inputSplits.getCount() >= 2)
236    {
237      if (objectList != NULL)
238      {
239        // Checking for a Match in the Objects of classID (else take the first)
240        tIterator<BaseObject>* itBO = objectList->getIterator();
241        BaseObject* enumBO = itBO->firstElement();
242        while(enumBO)
243        {
244          if (enumBO->getName() != NULL && !strcasecmp(enumBO->getName(), inputSplits.getString(1)))
245          {
246            objectPointer = enumBO;
247            fktPos = 2;
248            break;
249          }
250          enumBO = itBO->nextElement();
251         }
252         delete itBO;
253
254      //
255        if (objectPointer == NULL)
256          objectPointer = objectList->firstElement();
257      }
258      // match a function.
259      if (commandClass != NULL && (fktPos == 1 || (fktPos == 2 && inputSplits.getCount() >= 3)))
260      {
261        tIterator<ShellCommand>* itCMD = commandClass->commandList->getIterator();
262        ShellCommand* enumCMD = itCMD->firstElement();
263        while (enumCMD != NULL)
264        {
265          if (!strcmp(enumCMD->getName(), inputSplits.getString(fktPos)))
266          {
267            if (objectPointer == NULL && enumCMD->executor->getType() == Executor_Objective)
268            {
269              delete itCMD;
270              return false;
271            }
272            if (inputSplits.getCount() > fktPos+1)
273              enumCMD->executor->execute(objectPointer, executionString+inputSplits.getOffset(fktPos +1));
274            else
275              enumCMD->executor->execute(objectPointer, "");
276            delete itCMD;
277            return true;
278          }
279
280          enumCMD = itCMD->nextElement();
281        }
282        delete itCMD;
283      }
284    }
285  }
286}
287
288/**
289 * lets a command be described
290 * @param description the description of the Given command
291 */
292ShellCommand* ShellCommand::describe(const char* description)
293{
294  if (this == NULL)
295    return NULL;
296 else
297 {
298   this->description = description;
299   return this;
300 }
301}
302
303/**
304 * adds an Alias to this Command
305 * @param alias the name of the Alias to set
306 * @returns itself
307 */
308ShellCommand* ShellCommand::setAlias(const char* alias)
309{
310  if (this == NULL)
311    return NULL;
312
313  if (this->alias != NULL)
314  {
315    PRINTF(2)("not more than one Alias allowed for functions (%s::%s)\n", this->getName(), this->shellClass->getName());
316  }
317  else
318  {
319    if (ShellCommandClass::aliasList == NULL)
320      ShellCommandClass::aliasList = new tList<ShellCommandAlias>;
321
322    ShellCommandAlias* aliasCMD = new ShellCommandAlias(alias, this);
323    ShellCommandClass::aliasList->add(aliasCMD);
324    this->alias = aliasCMD;
325  }
326  return this;
327}
328
329/**
330 * sets default Values of the Commands
331 * @param count how many default Values to set.
332 * @param ... the default Values in order. They will be cast to the right type
333 * @returns itself
334 *
335 * Be aware, that when you use this Function, you !!MUST!! match the input as
336 * count, [EXACTLY THE SAME AS IF YOU WOULD CALL THE FUNCTION UP TO count ARGUMENTS]
337 */
338ShellCommand* ShellCommand::defaultValues(unsigned int count, ...)
339{
340  if (this == NULL)
341    return NULL;
342
343  va_list values;
344  va_start(values, count);
345
346  this->executor->defaultValues(count, values);
347
348  return this;
349}
350
351/**
352 * prints out nice information about the Shells Commands
353 */
354void ShellCommand::debug()
355{
356  if (ShellCommandClass::commandClassList == NULL)
357  {
358    PRINT(0)("No Command registered.\n");
359    return;
360  }
361
362  tIterator<ShellCommandClass>* iteratorCL = ShellCommandClass::commandClassList->getIterator();
363  ShellCommandClass* elemCL = iteratorCL->firstElement();
364  while(elemCL != NULL)
365  {
366    PRINT(0)("Class:'%s' registered %d commands: \n", elemCL->className, elemCL->commandList->getSize());
367    tIterator<ShellCommand>* iterator = elemCL->commandList->getIterator();
368    const ShellCommand* elem = iterator->firstElement();
369    while(elem != NULL)
370    {
371      PRINT(0)("  command:'%s' : params:%d: ", elem->getName(), elem->paramCount);
372      for (unsigned int i = 0; i< elem->paramCount; i++)
373       printf("%s ", ShellCommand::paramToString(elem->parameters[i]));
374      if (elem->description != NULL)
375       printf("- %s", elem->description);
376      printf("\n");
377
378      elem = iterator->nextElement();
379    }
380    delete iterator;
381    elemCL = iteratorCL->nextElement();
382  }
383  delete iteratorCL;
384}
385
386/**
387 * converts a Parameter to a String
388 * @param parameter the Parameter we have.
389 * @returns the Name of the Parameter at Hand
390 */
391const char* ShellCommand::paramToString(long parameter)
392{
393  return MultiType::MultiTypeToString((MT_Type)parameter);
394// FIXME
395  /*  switch (parameter)
396  {
397    case ParameterBool:
398      return "BOOL";
399      break;
400    case ParameterChar:
401      return "CHAR";
402      break;
403    case ParameterString:
404      return "STRING";
405      break;
406    case ParameterInt:
407      return "INT";
408      break;
409    case ParameterUInt:
410      return "UINT";
411      break;
412    case ParameterFloat:
413      return "FLOAT";
414      break;
415    case ParameterLong:
416      return "LONG";
417      break;
418    default:
419      return "NULL";
420      break;
421  }*/
422}
Note: See TracBrowser for help on using the repository browser.