Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5636 was 5636, checked in by bensch, 18 years ago

orxonox/trunk: adapting ShellCommand to use Executor.
On the go

File size: 19.5 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
20#include "list.h"
21#include "debug.h"
22#include "class_list.h"
23
24#include "key_names.h"
25#include <stdarg.h>
26#include <stdio.h>
27#include <string.h>
28
29using namespace std;
30
31/**
32 * creates a new ShellCommandClass
33 * @param className the Name of the command-class to create
34 */
35ShellCommandClass::ShellCommandClass(const char* className)
36{
37  this->setClassID(CL_SHELL_COMMAND_CLASS, "ShellCommandClass");
38  this->setName(className);
39
40  this->className = className;
41  this->classID = CL_NULL;
42  this->commandList = new tList<ShellCommand>;
43
44  ShellCommandClass::commandClassList->add(this);
45}
46
47/**
48 * destructs the shellCommandClass again
49 */
50ShellCommandClass::~ShellCommandClass()
51{
52  tIterator<ShellCommand>* iterator = this->commandList->getIterator();
53  ShellCommand* elem = iterator->firstElement();
54  while(elem != NULL)
55  {
56    delete elem;
57    elem = iterator->nextElement();
58  }
59  delete iterator;
60  delete this->commandList;
61}
62
63/**
64 * collects the Commands registered to some class.
65 * @param className the name of the Class to collect the Commands from.
66 * @param stringList a List to paste the Commands into.
67 * @returns true on success, false otherwise
68 */
69bool ShellCommandClass::getCommandListOfClass(const char* className, tList<const char>* stringList)
70{
71  if (stringList == NULL || className == NULL)
72    return false;
73
74  tIterator<ShellCommandClass>* iterator = ShellCommandClass::commandClassList->getIterator();
75  ShellCommandClass* elem = iterator->firstElement();
76  while(elem != NULL)
77  {
78    if (!strcmp (elem->getName(), className))
79    {
80      tIterator<ShellCommand>* itFkt = elem->commandList->getIterator();
81      ShellCommand* command = itFkt->firstElement();
82      while (command != NULL)
83      {
84        stringList->add(command->getName());
85        command = itFkt->nextElement();
86      }
87      delete itFkt;
88    }
89
90    elem = iterator->nextElement();
91  }
92  delete iterator;
93  return true;
94}
95
96/**
97 * collects the Aliases registered to the ShellCommands
98 * @param stringList a List to paste the Aliases into.
99 * @returns true on success, false otherwise
100 */
101bool ShellCommandClass::getCommandListOfAlias(tList<const char>* stringList)
102{
103  if (stringList == NULL || ShellCommandClass::aliasList == NULL)
104    return false;
105
106  tIterator<ShellCommandAlias>* iterator = ShellCommandClass::aliasList->getIterator();
107   ShellCommandAlias* elem = iterator->firstElement();
108   while(elem != NULL)
109   {
110     stringList->add(elem->getName());
111     elem = iterator->nextElement();
112   }
113   delete iterator;
114   return true;
115}
116
117/**
118 * unregisters all Commands that exist
119 */
120void ShellCommandClass::unregisterAllCommands()
121{
122  if (ShellCommandClass::commandClassList != NULL)
123  {
124    // unregister all commands
125    tIterator<ShellCommandClass>* iterator = ShellCommandClass::commandClassList->getIterator();
126    ShellCommandClass* elem = iterator->firstElement();
127    while(elem != NULL)
128    {
129      delete elem;
130
131      elem = iterator->nextElement();
132    }
133    delete iterator;
134
135    delete ShellCommandClass::commandClassList;
136    ShellCommandClass::commandClassList = NULL;
137  }
138
139  // unregister all aliases (there should be nothing to do here :))
140  if (ShellCommandClass::aliasList != NULL)
141  {
142    tIterator<ShellCommandAlias>* itAL = ShellCommandClass::aliasList->getIterator();
143    ShellCommandAlias* elemAL = itAL->firstElement();
144    while(elemAL != NULL)
145    {
146      delete elemAL;
147      elemAL = itAL->nextElement();
148    }
149    delete itAL;
150    delete ShellCommandClass::aliasList;
151    ShellCommandClass::aliasList = NULL;
152  }
153}
154
155/**
156 * checks if a Class is already registered to the Commands' class-stack
157 * @param className the Name of the Class to check for
158 * @returns the CommandClass if found, NULL otherwise
159 */
160const ShellCommandClass* ShellCommandClass::isRegistered(const char* className)
161{
162  if (ShellCommandClass::commandClassList == NULL)
163    initCommandClassList();
164
165  tIterator<ShellCommandClass>* iterator = ShellCommandClass::commandClassList->getIterator();
166  ShellCommandClass* elem = iterator->firstElement();
167  while(elem != NULL)
168  {
169    if (!strcmp(className, elem->className))
170    {
171      if (elem->classID == CL_NULL)
172        elem->classID = ClassList::StringToID(className);
173
174      delete iterator;
175      return elem;
176    }
177    elem = iterator->nextElement();
178  }
179  delete iterator;
180  return NULL;
181}
182
183/**
184 * searches for a CommandClass
185 * @param className the name of the CommandClass
186 * @returns the CommandClass if found, or a new CommandClass if not
187 */
188ShellCommandClass* ShellCommandClass::getCommandClass(const char* className)
189{
190  if (ShellCommandClass::commandClassList == NULL)
191    initCommandClassList();
192
193  tIterator<ShellCommandClass>* iterator = ShellCommandClass::commandClassList->getIterator();
194  ShellCommandClass* elem = iterator->firstElement();
195  while(elem != NULL)
196  {
197    if (!strcmp(className, elem->className))
198    {
199      delete iterator;
200      return elem;
201    }
202    elem = iterator->nextElement();
203  }
204  delete iterator;
205  return new ShellCommandClass(className);
206}
207
208/**
209 * initializes the CommandList (if it is NULL)
210 */
211void ShellCommandClass::initCommandClassList()
212{
213  if (ShellCommandClass::commandClassList == NULL)
214  {
215    ShellCommandClass::commandClassList = new tList<ShellCommandClass>;
216    ShellCommand::registerCommand("debug", "ShellCommand", new ExecutorStatic<ShellCommand>(ShellCommand::debug));
217  }
218}
219
220void ShellCommandClass::help(const char* className)
221{
222  if (className == NULL)
223    return;
224  if (likely(ShellCommandClass::commandClassList != NULL))
225  {
226    tIterator<ShellCommandClass>* itCL = ShellCommandClass::commandClassList->getIterator();
227    ShellCommandClass* elemCL = itCL->firstElement();
228    while(elemCL != NULL)
229    {
230      if (elemCL->className && !strcasecmp(className, elemCL->className))
231      {
232        PRINT(0)("Class:'%s' registered %d commands: \n", elemCL->className, elemCL->commandList->getSize());
233        tIterator<ShellCommand>* iterator = elemCL->commandList->getIterator();
234        const ShellCommand* elem = iterator->firstElement();
235        while(elem != NULL)
236        {
237          PRINT(0)("  command:'%s' : params:%d: ", elem->getName(), elem->paramCount);
238          for (unsigned int i = 0; i< elem->paramCount; i++)
239            PRINT(0)("%s ", ShellCommand::paramToString(elem->parameters[i]));
240          if (elem->description != NULL)
241            PRINT(0)("- %s", elem->description);
242          PRINT(0)("\n");
243          elem = iterator->nextElement();
244        }
245        delete iterator;
246
247        delete itCL;
248        return;
249      }
250      elemCL = itCL->nextElement();
251    }
252    delete itCL;
253    PRINTF(3)("Class %s not found in Command's classes\n", className);
254  }
255  else
256  {
257    PRINTF(1)("List of commandClasses does not exist");
258  }
259}
260
261tList<ShellCommandClass>* ShellCommandClass::commandClassList = NULL;
262tList<ShellCommandAlias>* ShellCommandClass::aliasList = NULL;
263
264
265
266
267
268
269
270
271
272
273////////////////////////
274// SHELL COMMAND BASE //
275////////////////////////
276/**
277 * constructs and registers a new Command
278 * @param commandName the name of the Command
279 * @param className the name of the class to apply this command to
280 * @param paramCount the count of parameters this command takes
281 */
282ShellCommand::ShellCommand(const char* commandName, const char* className, unsigned int paramCount, ...)
283{
284  this->setClassID(CL_SHELL_COMMAND, "ShellCommand");
285  this->setName(commandName);
286  this->description = NULL;
287  this->alias = NULL;
288
289//  this->classID = classID;
290  this->shellClass = ShellCommandClass::getCommandClass(className); //ClassList::IDToString(classID);
291  if (this->shellClass != NULL)
292    this->shellClass->commandList->add(this);
293  // handling parameters, and storing them:
294  if (paramCount > FUNCTOR_MAX_ARGUMENTS)
295    paramCount = FUNCTOR_MAX_ARGUMENTS;
296  this->paramCount = paramCount;
297  this->parameters = new unsigned int[paramCount];
298  this->defaultValue = new MultiType[paramCount];
299
300  va_list parameterList;
301  va_start(parameterList, paramCount);
302
303  // What Parameters we have got
304  for (unsigned int i = 0; i < paramCount; i++)
305    this->parameters[i] = va_arg(parameterList, int);
306}
307
308/**
309 * deconstructs a ShellCommand
310 */
311ShellCommand::~ShellCommand()
312{
313  delete[] this->parameters;
314  delete[] this->defaultValue;
315  if (this->alias != NULL && ShellCommandClass::aliasList != NULL)
316  {
317    ShellCommandClass::aliasList->remove(this->alias);
318    delete this->alias;
319  }
320}
321
322/**
323 * registers a new ShellCommand
324 */
325ShellCommand* ShellCommand::registerCommand(const char* commandName, const char* className, Executor* executor)
326{
327  return NULL;
328
329}
330
331
332
333
334/**
335 * unregister an existing commandName
336 * @param className the name of the Class the command belongs to.
337 * @param commandName the name of the command itself
338 */
339void ShellCommand::unregisterCommand(const char* commandName, const char* className)
340{
341  if (ShellCommandClass::commandClassList == NULL)
342    ShellCommandClass::initCommandClassList();
343
344 const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
345
346 if (checkClass != NULL)
347  {
348    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
349    ShellCommand* elem = iterator->firstElement();
350    while(elem != NULL)
351    {
352      if (!strcmp(commandName, elem->getName()))
353      {
354        checkClass->commandList->remove(elem);
355        delete elem;
356        break;
357      }
358      elem = iterator->nextElement();
359    }
360    delete iterator;
361
362    if (checkClass->commandList->getSize() == 0)
363    {
364      ShellCommandClass::commandClassList->remove(checkClass);
365      delete checkClass;
366    }
367  }
368}
369
370/**
371 * checks if a command has already been registered.
372 * @param commandName the name of the Command
373 * @param className the name of the Class the command should apply to.
374 * @param paramCount how many arguments the Command takes
375 * @returns true, if the command is registered/false otherwise
376 *
377 * This is used internally, to see, if we have multiple command subscriptions.
378 * This is checked in the registerCommand-function.
379 */
380bool ShellCommand::isRegistered(const char* commandName, const char* className, unsigned int paramCount, ...)
381{
382  if (ShellCommandClass::commandClassList == NULL)
383  {
384    ShellCommandClass::initCommandClassList();
385    return false;
386  }
387
388  const ShellCommandClass* checkClass = ShellCommandClass::isRegistered(className);
389  if (checkClass != NULL)
390  {
391    tIterator<ShellCommand>* iterator = checkClass->commandList->getIterator();
392    ShellCommand* elem = iterator->firstElement();
393    while(elem != NULL)
394   {
395     if (!strcmp(commandName, elem->getName()))
396     {
397       PRINTF(2)("Command already registered\n");
398       delete iterator;
399       return true;
400      }
401     elem = iterator->nextElement();
402   }
403   delete iterator;
404   return false;
405  }
406  else
407    return false;
408}
409
410
411/**
412 * executes commands
413 * @param executionString the string containing the following input
414 * ClassName [ObjectName] functionName [parameter1[,parameter2[,...]]]
415 * @return true on success, false otherwise.
416 */
417bool ShellCommand::execute(const char* executionString)
418{
419  if (ShellCommandClass::commandClassList == NULL)
420    return false;
421
422  long classID = CL_NULL;                 //< the classID retrieved from the Class.
423  ShellCommandClass* commandClass = NULL; //< the command class this command applies to.
424  tList<BaseObject>* objectList = NULL;   //< the list of Objects stored in classID
425  BaseObject* objectPointer = NULL;       //< a pointer to th Object to Execute the command on
426  bool emptyComplete = false;             //< if the completion input is empty string. e.g ""
427  unsigned int fktPos = 1;                //< the position of the function (needed for finding it)
428//  long completeType = SHELLC_NONE;      //< the Type we'd like to complete.
429  SubString inputSplits(executionString, true);
430
431  if (inputSplits.getCount() == 0)
432    return false;
433  if (inputSplits.getCount() >= 1)
434  {
435    // CHECK FOR ALIAS
436    if (ShellCommandClass::aliasList != NULL)
437    {
438      tIterator<ShellCommandAlias>* itAL = ShellCommandClass::aliasList->getIterator();
439      ShellCommandAlias* elemAL = itAL->firstElement();
440      while(elemAL != NULL)
441      {
442        if (elemAL->getName() != NULL && !strcmp(elemAL->getName(), inputSplits.getString(0)) && elemAL->getCommand() != NULL &&
443            elemAL->getCommand()->shellClass != NULL )
444        {
445          objectList = ClassList::getList(elemAL->getCommand()->shellClass->getName());
446          if (objectList != NULL)
447          {
448            if (inputSplits.getCount() > 1)
449              elemAL->getCommand()->executeCommand(objectList->firstElement(), executionString+inputSplits.getOffset(1));
450            else
451              elemAL->getCommand()->executeCommand(objectList->firstElement(), "");
452            delete itAL;
453            return true;
454          }
455        }
456        elemAL = itAL->nextElement();
457      }
458      delete itAL;
459    }
460    // looking for a Matching Class
461    if (likely(ShellCommandClass::commandClassList != NULL))
462    {
463      tIterator<ShellCommandClass>* itCL = ShellCommandClass::commandClassList->getIterator();
464      ShellCommandClass* elemCL = itCL->firstElement();
465      while(elemCL != NULL)
466      {
467        if (elemCL->getName() && !strcasecmp(inputSplits.getString(0), elemCL->getName()))
468        {
469          //elemCL->getName();
470          classID = ClassList::StringToID(elemCL->getName());
471          commandClass = elemCL;
472          objectList = ClassList::getList(classID);
473          break;
474        }
475        elemCL = itCL->nextElement();
476      }
477      delete itCL;
478    }
479
480    if (commandClass != NULL && inputSplits.getCount() >= 2)
481    {
482      if (objectList != NULL)
483      {
484        // Checking for a Match in the Objects of classID (else take the first)
485        tIterator<BaseObject>* itBO = objectList->getIterator();
486        BaseObject* enumBO = itBO->firstElement();
487        while(enumBO)
488        {
489          if (enumBO->getName() != NULL && !strcasecmp(enumBO->getName(), inputSplits.getString(1)))
490          {
491            objectPointer = enumBO;
492            fktPos = 2;
493            break;
494          }
495          enumBO = itBO->nextElement();
496         }
497         delete itBO;
498
499      //
500        if (objectPointer == NULL)
501          objectPointer = objectList->firstElement();
502      }
503      // match a function.
504      if (commandClass != NULL && (fktPos == 1 || (fktPos == 2 && inputSplits.getCount() >= 3)))
505      {
506        tIterator<ShellCommand>* itCMD = commandClass->commandList->getIterator();
507        ShellCommand* enumCMD = itCMD->firstElement();
508        while (enumCMD != NULL)
509        {
510          if (!strcmp(enumCMD->getName(), inputSplits.getString(fktPos)))
511          {
512            if (objectPointer == NULL && enumCMD->functorType == ShellCommand_Objective)
513            {
514              delete itCMD;
515              return false;
516            }
517            if (inputSplits.getCount() > fktPos+1)
518              enumCMD->executeCommand(objectPointer, executionString+inputSplits.getOffset(fktPos +1));
519            else
520              enumCMD->executeCommand(objectPointer, "");
521            delete itCMD;
522            return true;
523          }
524
525          enumCMD = itCMD->nextElement();
526        }
527        delete itCMD;
528      }
529    }
530  }
531}
532
533/**
534 * lets a command be described
535 * @param description the description of the Given command
536 */
537ShellCommand* ShellCommand::describe(const char* description)
538{
539  if (this == NULL)
540    return NULL;
541 else
542 {
543   this->description = description;
544   return this;
545 }
546}
547
548/**
549 * adds an Alias to this Command
550 * @param alias the name of the Alias to set
551 * @returns itself
552 */
553ShellCommand* ShellCommand::setAlias(const char* alias)
554{
555  if (this == NULL)
556    return NULL;
557
558  if (this->alias != NULL)
559  {
560    PRINTF(2)("not more than one Alias allowed for functions (%s::%s)\n", this->getName(), this->shellClass->getName());
561  }
562  else
563  {
564    if (ShellCommandClass::aliasList == NULL)
565      ShellCommandClass::aliasList = new tList<ShellCommandAlias>;
566
567    ShellCommandAlias* aliasCMD = new ShellCommandAlias(alias, this);
568    ShellCommandClass::aliasList->add(aliasCMD);
569    this->alias = aliasCMD;
570  }
571  return this;
572}
573
574/**
575 * sets default Values of the Commands
576 * @param count how many default Values to set.
577 * @param ... the default Values in order. They will be cast to the right type
578 * @returns itself
579 *
580 * Be aware, that when you use this Function, you !!MUST!! match the input as
581 * count, [EXACTLY THE SAME AS IF YOU WOULD CALL THE FUNCTION UP TO count ARGUMENTS]
582 */
583ShellCommand* ShellCommand::defaultValues(unsigned int count, ...)
584{
585  if (this == NULL)
586    return NULL;
587  if (count == 0)
588    return this;
589  if (count > this->paramCount)
590    count = this->paramCount;
591
592  va_list defaultList;
593  va_start(defaultList, count);
594
595  for (unsigned int i = 0; i < count; i++)
596  {
597
598
599    switch (this->parameters[i])
600    {
601      case MT_BOOL:
602        this->defaultValue[i].setInt(va_arg(defaultList, int));
603        break;
604      case MT_CHAR:
605        this->defaultValue[i].setChar((char)va_arg(defaultList, int));
606        break;
607      case MT_STRING:
608        this->defaultValue[i].setString(va_arg(defaultList, char*));
609        break;
610      case MT_INT:
611        this->defaultValue[i].setInt(va_arg(defaultList, int));
612        break;
613/*      case MT_UINT:
614        this->defaultValue[i].setInt((int)va_arg(defaultList, unsigned int));
615        break;*/
616      case MT_FLOAT:
617        this->defaultValue[i].setFloat(va_arg(defaultList, double));
618        break;
619/*      case MT_LONG:
620        this->defaultValue[i].setInt((int) va_arg(defaultList, long));
621        break;*/
622      default:
623        break;
624    }
625  }
626  return this;
627}
628
629/**
630 * prints out nice information about the Shells Commands
631 */
632void ShellCommand::debug()
633{
634  if (ShellCommandClass::commandClassList == NULL)
635  {
636    PRINT(0)("No Command registered.\n");
637    return;
638  }
639
640  tIterator<ShellCommandClass>* iteratorCL = ShellCommandClass::commandClassList->getIterator();
641  ShellCommandClass* elemCL = iteratorCL->firstElement();
642  while(elemCL != NULL)
643  {
644    PRINT(0)("Class:'%s' registered %d commands: \n", elemCL->className, elemCL->commandList->getSize());
645    tIterator<ShellCommand>* iterator = elemCL->commandList->getIterator();
646    const ShellCommand* elem = iterator->firstElement();
647    while(elem != NULL)
648    {
649      PRINT(0)("  command:'%s' : params:%d: ", elem->getName(), elem->paramCount);
650      for (unsigned int i = 0; i< elem->paramCount; i++)
651       printf("%s ", ShellCommand::paramToString(elem->parameters[i]));
652      if (elem->description != NULL)
653       printf("- %s", elem->description);
654      printf("\n");
655
656      elem = iterator->nextElement();
657    }
658    delete iterator;
659    elemCL = iteratorCL->nextElement();
660  }
661  delete iteratorCL;
662}
663
664/**
665 * converts a Parameter to a String
666 * @param parameter the Parameter we have.
667 * @returns the Name of the Parameter at Hand
668 */
669const char* ShellCommand::paramToString(long parameter)
670{
671  return MultiType::MultiTypeToString((MT_Type)parameter);
672// FIXME
673  /*  switch (parameter)
674  {
675    case ParameterBool:
676      return "BOOL";
677      break;
678    case ParameterChar:
679      return "CHAR";
680      break;
681    case ParameterString:
682      return "STRING";
683      break;
684    case ParameterInt:
685      return "INT";
686      break;
687    case ParameterUInt:
688      return "UINT";
689      break;
690    case ParameterFloat:
691      return "FLOAT";
692      break;
693    case ParameterLong:
694      return "LONG";
695      break;
696    default:
697      return "NULL";
698      break;
699  }*/
700}
Note: See TracBrowser for help on using the repository browser.