Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: splitted shell_command into shell_command and shell_command_class

File size: 12.9 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, 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;
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}
72
73/**
74 * registers a new ShellCommand
75 */
76ShellCommand* ShellCommand::registerCommand(const char* commandName, const char* className, Executor* executor)
77{
78  if (ShellCommand::isRegistered(commandName, className, executor))
79    return NULL;
80  else
81    return new ShellCommand(commandName, className, executor);
82
83}
84
85
86
87
88/**
89 * unregister an existing commandName
90 * @param className the name of the Class the command belongs to.
91 * @param commandName the name of the command itself
92 */
93void ShellCommand::unregisterCommand(const char* commandName, const char* className)
94{
95  if (ShellCommandClass::commandClassList == NULL)
96    ShellCommandClass::initCommandClassList();
97
98 const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
99
100 if (checkClass != NULL)
101  {
102    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
103    ShellCommand* elem = iterator->firstElement();
104    while(elem != NULL)
105    {
106      if (!strcmp(commandName, elem->getName()))
107      {
108        checkClass->commandList->remove(elem);
109        delete elem;
110        break;
111      }
112      elem = iterator->nextElement();
113    }
114    delete iterator;
115
116    if (checkClass->commandList->getSize() == 0)
117    {
118      ShellCommandClass::commandClassList->remove(checkClass);
119      delete checkClass;
120    }
121  }
122}
123
124/**
125 * checks if a command has already been registered.
126 * @param commandName the name of the Command
127 * @param className the name of the Class the command should apply to.
128 * @param paramCount how many arguments the Command takes
129 * @returns true, if the command is registered/false otherwise
130 *
131 * This is used internally, to see, if we have multiple command subscriptions.
132 * This is checked in the registerCommand-function.
133 */
134bool ShellCommand::isRegistered(const char* commandName, const char* className, Executor* executor)
135{
136  if (ShellCommandClass::commandClassList == NULL)
137  {
138    ShellCommandClass::initCommandClassList();
139    return false;
140  }
141
142  const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
143  if (checkClass != NULL)
144  {
145    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
146    ShellCommand* elem = iterator->firstElement();
147    while(elem != NULL)
148   {
149     if (!strcmp(commandName, elem->getName()))
150     {
151       PRINTF(2)("Command already registered\n");
152       delete iterator;
153       return true;
154      }
155     elem = iterator->nextElement();
156   }
157   delete iterator;
158   return false;
159  }
160  else
161    return false;
162}
163
164
165/**
166 * executes commands
167 * @param executionString the string containing the following input
168 * ClassName [ObjectName] functionName [parameter1[,parameter2[,...]]]
169 * @return true on success, false otherwise.
170 */
171bool ShellCommand::execute(const char* executionString)
172{
173  if (ShellCommandClass::commandClassList == NULL)
174    return false;
175
176  long classID = CL_NULL;                 //< the classID retrieved from the Class.
177  ShellCommandClass* commandClass = NULL; //< the command class this command applies to.
178  tList<BaseObject>* objectList = NULL;   //< the list of Objects stored in classID
179  BaseObject* objectPointer = NULL;       //< a pointer to th Object to Execute the command on
180  bool emptyComplete = false;             //< if the completion input is empty string. e.g ""
181  unsigned int fktPos = 1;                //< the position of the function (needed for finding it)
182//  long completeType = SHELLC_NONE;      //< the Type we'd like to complete.
183  SubString inputSplits(executionString, true);
184
185  if (inputSplits.getCount() == 0)
186    return false;
187  if (inputSplits.getCount() >= 1)
188  {
189    // CHECK FOR ALIAS
190    if (ShellCommandClass::aliasList != NULL)
191    {
192      tIterator<ShellCommandAlias>* itAL = ShellCommandClass::aliasList->getIterator();
193      ShellCommandAlias* elemAL = itAL->firstElement();
194      while(elemAL != NULL)
195      {
196        if (elemAL->getName() != NULL && !strcmp(elemAL->getName(), inputSplits.getString(0)) && elemAL->getCommand() != NULL &&
197            elemAL->getCommand()->shellClass != NULL )
198        {
199          objectList = ClassList::getList(elemAL->getCommand()->shellClass->getName());
200          if (objectList != NULL)
201          {
202            if (inputSplits.getCount() > 1)
203              elemAL->getCommand()->executor->execute(objectList->firstElement(), executionString+inputSplits.getOffset(1));
204            else
205              elemAL->getCommand()->executor->execute(objectList->firstElement(), "");
206            delete itAL;
207            return true;
208          }
209        }
210        elemAL = itAL->nextElement();
211      }
212      delete itAL;
213    }
214    // looking for a Matching Class
215    if (likely(ShellCommandClass::commandClassList != NULL))
216    {
217      tIterator<ShellCommandClass>* itCL = ShellCommandClass::commandClassList->getIterator();
218      ShellCommandClass* elemCL = itCL->firstElement();
219      while(elemCL != NULL)
220      {
221        if (elemCL->getName() && !strcasecmp(inputSplits.getString(0), elemCL->getName()))
222        {
223          //elemCL->getName();
224          classID = ClassList::StringToID(elemCL->getName());
225          commandClass = elemCL;
226          objectList = ClassList::getList(classID);
227          break;
228        }
229        elemCL = itCL->nextElement();
230      }
231      delete itCL;
232    }
233
234    if (commandClass != NULL && inputSplits.getCount() >= 2)
235    {
236      if (objectList != NULL)
237      {
238        // Checking for a Match in the Objects of classID (else take the first)
239        tIterator<BaseObject>* itBO = objectList->getIterator();
240        BaseObject* enumBO = itBO->firstElement();
241        while(enumBO)
242        {
243          if (enumBO->getName() != NULL && !strcasecmp(enumBO->getName(), inputSplits.getString(1)))
244          {
245            objectPointer = enumBO;
246            fktPos = 2;
247            break;
248          }
249          enumBO = itBO->nextElement();
250         }
251         delete itBO;
252
253      //
254        if (objectPointer == NULL)
255          objectPointer = objectList->firstElement();
256      }
257      // match a function.
258      if (commandClass != NULL && (fktPos == 1 || (fktPos == 2 && inputSplits.getCount() >= 3)))
259      {
260        tIterator<ShellCommand>* itCMD = commandClass->commandList->getIterator();
261        ShellCommand* enumCMD = itCMD->firstElement();
262        while (enumCMD != NULL)
263        {
264          if (!strcmp(enumCMD->getName(), inputSplits.getString(fktPos)))
265          {
266            if (objectPointer == NULL && enumCMD->functorType == ShellCommand_Objective)
267            {
268              delete itCMD;
269              return false;
270            }
271            if (inputSplits.getCount() > fktPos+1)
272              enumCMD->executor->execute(objectPointer, executionString+inputSplits.getOffset(fktPos +1));
273            else
274              enumCMD->executor->execute(objectPointer, "");
275            delete itCMD;
276            return true;
277          }
278
279          enumCMD = itCMD->nextElement();
280        }
281        delete itCMD;
282      }
283    }
284  }
285}
286
287/**
288 * lets a command be described
289 * @param description the description of the Given command
290 */
291ShellCommand* ShellCommand::describe(const char* description)
292{
293  if (this == NULL)
294    return NULL;
295 else
296 {
297   this->description = description;
298   return this;
299 }
300}
301
302/**
303 * adds an Alias to this Command
304 * @param alias the name of the Alias to set
305 * @returns itself
306 */
307ShellCommand* ShellCommand::setAlias(const char* alias)
308{
309  if (this == NULL)
310    return NULL;
311
312  if (this->alias != NULL)
313  {
314    PRINTF(2)("not more than one Alias allowed for functions (%s::%s)\n", this->getName(), this->shellClass->getName());
315  }
316  else
317  {
318    if (ShellCommandClass::aliasList == NULL)
319      ShellCommandClass::aliasList = new tList<ShellCommandAlias>;
320
321    ShellCommandAlias* aliasCMD = new ShellCommandAlias(alias, this);
322    ShellCommandClass::aliasList->add(aliasCMD);
323    this->alias = aliasCMD;
324  }
325  return this;
326}
327
328/**
329 * sets default Values of the Commands
330 * @param count how many default Values to set.
331 * @param ... the default Values in order. They will be cast to the right type
332 * @returns itself
333 *
334 * Be aware, that when you use this Function, you !!MUST!! match the input as
335 * count, [EXACTLY THE SAME AS IF YOU WOULD CALL THE FUNCTION UP TO count ARGUMENTS]
336 */
337ShellCommand* ShellCommand::defaultValues(unsigned int count, ...)
338{
339  if (this == NULL)
340    return NULL;
341  if (count == 0)
342    return this;
343  if (count > this->paramCount)
344    count = this->paramCount;
345
346  va_list defaultList;
347  va_start(defaultList, count);
348
349  for (unsigned int i = 0; i < count; i++)
350  {
351
352
353    switch (this->parameters[i])
354    {
355      case MT_BOOL:
356        this->defaultValue[i].setInt(va_arg(defaultList, int));
357        break;
358      case MT_CHAR:
359        this->defaultValue[i].setChar((char)va_arg(defaultList, int));
360        break;
361      case MT_STRING:
362        this->defaultValue[i].setString(va_arg(defaultList, char*));
363        break;
364      case MT_INT:
365        this->defaultValue[i].setInt(va_arg(defaultList, int));
366        break;
367/*      case MT_UINT:
368        this->defaultValue[i].setInt((int)va_arg(defaultList, unsigned int));
369        break;*/
370      case MT_FLOAT:
371        this->defaultValue[i].setFloat(va_arg(defaultList, double));
372        break;
373/*      case MT_LONG:
374        this->defaultValue[i].setInt((int) va_arg(defaultList, long));
375        break;*/
376      default:
377        break;
378    }
379  }
380  return this;
381}
382
383/**
384 * prints out nice information about the Shells Commands
385 */
386void ShellCommand::debug()
387{
388  if (ShellCommandClass::commandClassList == NULL)
389  {
390    PRINT(0)("No Command registered.\n");
391    return;
392  }
393
394  tIterator<ShellCommandClass>* iteratorCL = ShellCommandClass::commandClassList->getIterator();
395  ShellCommandClass* elemCL = iteratorCL->firstElement();
396  while(elemCL != NULL)
397  {
398    PRINT(0)("Class:'%s' registered %d commands: \n", elemCL->className, elemCL->commandList->getSize());
399    tIterator<ShellCommand>* iterator = elemCL->commandList->getIterator();
400    const ShellCommand* elem = iterator->firstElement();
401    while(elem != NULL)
402    {
403      PRINT(0)("  command:'%s' : params:%d: ", elem->getName(), elem->paramCount);
404      for (unsigned int i = 0; i< elem->paramCount; i++)
405       printf("%s ", ShellCommand::paramToString(elem->parameters[i]));
406      if (elem->description != NULL)
407       printf("- %s", elem->description);
408      printf("\n");
409
410      elem = iterator->nextElement();
411    }
412    delete iterator;
413    elemCL = iteratorCL->nextElement();
414  }
415  delete iteratorCL;
416}
417
418/**
419 * converts a Parameter to a String
420 * @param parameter the Parameter we have.
421 * @returns the Name of the Parameter at Hand
422 */
423const char* ShellCommand::paramToString(long parameter)
424{
425  return MultiType::MultiTypeToString((MT_Type)parameter);
426// FIXME
427  /*  switch (parameter)
428  {
429    case ParameterBool:
430      return "BOOL";
431      break;
432    case ParameterChar:
433      return "CHAR";
434      break;
435    case ParameterString:
436      return "STRING";
437      break;
438    case ParameterInt:
439      return "INT";
440      break;
441    case ParameterUInt:
442      return "UINT";
443      break;
444    case ParameterFloat:
445      return "FLOAT";
446      break;
447    case ParameterLong:
448      return "LONG";
449      break;
450    default:
451      return "NULL";
452      break;
453  }*/
454}
Note: See TracBrowser for help on using the repository browser.