Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/shell/shell_completion.cc @ 5254

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

orxonox/trunk: some very little todo's…, and Names in all files

File size: 11.0 KB
RevLine 
[4744]1/*
[1853]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.
[1855]10
11   ### File Specific:
[5254]12   main-programmer: Benjamin Grauer
[1855]13   co-programmer: ...
[1853]14*/
15
[3955]16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
[1853]17
[5170]18#include "shell_completion.h"
[1853]19
[5181]20#include "shell_input.h"
[5194]21#include "shell_command.h"
[5181]22
[5183]23#include "substring.h"
[5178]24#include "base_object.h"
25#include "class_list.h"
26#include "list.h"
27#include "debug.h"
28
29#include "stdlibincl.h"
30
[1856]31using namespace std;
[1853]32
[3245]33/**
[4838]34 * standard constructor
[3245]35*/
[5182]36ShellCompletion::ShellCompletion(ShellInput* input)
[3365]37{
[5181]38  this->completionList = NULL;
[5182]39  this->input = input;
[3365]40}
[1853]41
42
[3245]43/**
[4838]44 * standard deconstructor
[3245]45*/
[5170]46ShellCompletion::~ShellCompletion ()
[3543]47{
48  // delete what has to be deleted here
[5181]49  if (this->completionList)
50  {
[5188]51    this->emptyCompletionList();
[5181]52    delete this->completionList;
53  }
[3543]54}
[5178]55
56
57
58/**
59 * autocompletes the Shell's inputLine
60 * @returns true, if a result was found, false otherwise
61 */
[5181]62bool ShellCompletion::autoComplete(ShellInput* input)
[5178]63{
[5194]64  const char* completionLine;      //< the inputLine we complete.
[5183]65
[5187]66  long classID;                    //< the classID retrieved from the Class.
67  tList<BaseObject>* objectList;   //< the list of Objects stored in classID
[5190]68  bool emptyComplete = false;      //< if the completion input is empty string. e.g ""
[5194]69  long completeType = SHELLC_NONE; //< the Type we'd like to complete.
70  const char* completeString;      //< the string to complete.
[5183]71
[5190]72
[5191]73  PRINTF(5)("AutoComplete on input\n");
[5187]74  this->emptyCompletionList();
[5185]75
[5182]76  if (input != NULL)
77    this->input = input;
[5184]78  if (this->input == NULL)
[5185]79  {
80    PRINTF(2)("No ShellInput supplied\n");
[5184]81    return false;
[5185]82  }
[5190]83
84  // Check if we are in a input. eg. the supplied string "class " and now we complete either function or object
[5191]85  if (this->input->getInput() != NULL &&
86      strrchr(this->input->getInput(), ' ') >= this->input->getInput() + strlen(this->input->getInput())-1)
[5190]87  {
88    emptyComplete = true;
89  }
90
[5193]91  // CREATE INPUTS
[5185]92  if (this->input->getInput() == NULL)
[5191]93    completionLine = "";
94  else
95    completionLine = this->input->getInput() + strspn(this->input->getInput(), " \t\n");
[5184]96  SubString inputSplits(completionLine, true);
97
[5193]98  // What String will be completed
99  if (emptyComplete == true)
100    completeString = "";
101  else
102    completeString = inputSplits.getString(inputSplits.getCount()-1);
103
[5185]104  // CLASS COMPLETION
[5184]105  if (inputSplits.getCount() == 0)
106  {
[5193]107    completeType |= SHELLC_CLASS;
[5195]108    completeType |= SHELLC_ALIAS;
109
[5184]110  }
[5191]111  else if (inputSplits.getCount() == 1 && emptyComplete == false)
[5184]112  {
[5193]113    completeType |= SHELLC_CLASS;
[5195]114    completeType |= SHELLC_ALIAS;
[5184]115  }
116
[5191]117  // OBJECT/FUNCTION COMPLETIONS
[5192]118  else if ((inputSplits.getCount() == 1 && emptyComplete == true) ||
119            (inputSplits.getCount() == 2 && emptyComplete == false))
[5184]120  {
[5185]121    classID = ClassList::StringToID(inputSplits.getString(0));
[5194]122    objectList = ClassList::getList(classID);
[5185]123    if (classID == CL_NULL)
124      return false;
[5192]125    else
[5186]126    {
[5194]127      if (objectList != NULL && objectList->getSize() == 1)
128        completeType |= SHELLC_FUNCTION;
[5193]129      completeType |= SHELLC_OBJECT;
[5186]130    }
[5184]131  }
[5194]132  else if ((inputSplits.getCount() == 2 && emptyComplete == true) ||
133            (inputSplits.getCount() == 3 && emptyComplete == false))
134  {
135    classID = ClassList::StringToID(inputSplits.getString(0));
136    if (classID == CL_NULL)
137      return false;
138    else
139     completeType |= SHELLC_FUNCTION;
140  }
[5184]141
[5193]142  if (completeType & SHELLC_CLASS)
143    this->objectComplete(completeString, CL_SHELL_COMMAND_CLASS);
144  if (completeType & SHELLC_OBJECT)
145    this->objectComplete(completeString, classID);
[5194]146  if (completeType & SHELLC_FUNCTION)
147    this->functionComplete(completeString, classID);
[5195]148  if (completeType & SHELLC_ALIAS)
149    this->aliasComplete(completeString);
[5193]150
[5194]151
152  this->generalComplete(completeString);
153  return true;
[5178]154}
155
156/**
157 * autocompletes a className
158 * @param classBegin the Beginning of a String to autoComplete
159 * @return true on success, false otherwise
160 */
161bool ShellCompletion::classComplete(const char* classBegin)
162{
163  if (unlikely(classBegin == NULL))
164    return false;
165  const tList<const char>* clList = ClassList::getClassList();
166  if (clList != NULL)
167  {
[5245]168    if (!this->addToCompleteList(clList, classBegin, SHELLC_CLASS))
[5178]169      return false;
170  }
171  else
172    return false;
173  return true;
174}
175
176/**
177 * autocompletes an ObjectName
178 * @param objectBegin the beginning string of a Object
179 * @param classID the ID of the Class to search for.
180 * @return true on success, false otherwise
181 */
182bool ShellCompletion::objectComplete(const char* objectBegin, long classID)
183{
184  if (unlikely(objectBegin == NULL))
185    return false;
[5193]186  const tList<BaseObject>* boList = ClassList::getList(classID);
[5178]187  if (boList != NULL)
188  {
[5245]189    SHELLC_TYPE type = SHELLC_OBJECT;
190    if (classID == CL_SHELL_COMMAND_CLASS)
191      type = SHELLC_CLASS;
192    if (!this->addToCompleteList(boList, objectBegin, type))
[5178]193      return false;
194  }
195  else
196    return false;
197  return true;
198}
199
200/**
201 * completes a Function
202 * @param functionBegin the beginning of the function String
[5197]203 * @param classID the class' ID to complete the function of
[5178]204 */
[5194]205bool ShellCompletion::functionComplete(const char* functionBegin, long classID)
[5178]206{
[5194]207  if (unlikely(functionBegin == NULL))
208    return false;
209  tList<const char> fktList;
210  ShellCommandClass::getCommandListOfClass(ClassList::IDToString(classID), &fktList);
211  //printf("%s\n", boList->firstElement()->getName());
[5245]212  if (!this->addToCompleteList(&fktList, functionBegin, SHELLC_FUNCTION))
[5194]213    return false;
214  return true;
[5178]215}
216
[5197]217/**
218 * completes an Alias
219 * @param aliasBegin the beginning of the Alias-String to complete
220 * @returns true on succes, false if something went wrong
221 */
[5195]222bool ShellCompletion::aliasComplete(const char* aliasBegin)
223{
224  if (unlikely(aliasBegin == NULL))
225    return false;
226  tList<const char> aliasList;
227  ShellCommandClass::getCommandListOfAlias(&aliasList);
228  //printf("%s\n", boList->firstElement()->getName());
[5245]229  if (!this->addToCompleteList(&aliasList, aliasBegin, SHELLC_ALIAS))
[5195]230    return false;
231  return true;
232}
233
234
[5178]235/**
236 * completes the inputline on grounds of an inputList
237 * @param begin the String to search in the inputList, and to extend with it.
238 * @param displayAs how to display the found value to the user, printf-style, !!with only one %s!! ex.: "::%s::"
239 * @param addBack what should be added at the end of the completion
240 * @param addFront what should be added to the front of one finished completion
241 * @return true if ok, false otherwise
242 */
[5192]243bool ShellCompletion::generalComplete(const char* begin, const char* displayAs, const char* addBack, const char* addFront)
[5178]244{
[5192]245  if (completionList == NULL || this->input == NULL )
[5185]246    return false;
[5192]247  if (completionList->getSize() == 0)
[5178]248    return false;
249
[5192]250  ShellC_Element* addElem = completionList->firstElement();
[5187]251  const char* addString = addElem->name;
[5178]252  unsigned int addLength = 0;
253  unsigned int inputLenght = strlen(begin);
254
[5187]255  // Determin the longest Match
[5178]256  if (addString != NULL)
257    addLength = strlen(addString);
[5192]258  tIterator<ShellC_Element>* charIterator = completionList->getIterator();
[5187]259  ShellC_Element* charElem = charIterator->firstElement();
[5245]260  SHELLC_TYPE changeType = SHELLC_NONE;
[5178]261  while (charElem != NULL)
262  {
[5245]263    if (charElem->type != changeType)
264    {
265      if (changeType != SHELLC_NONE)
266        PRINT(0)("\n");
267      PRINT(0)("%s: ", ShellCompletion::typeToString(charElem->type));
268      changeType = charElem->type;
269    }
270    PRINTF(0)("%s ", charElem->name);
[5178]271    for (unsigned int i = inputLenght; i < addLength; i++)
[5187]272      if (addString[i] != charElem->name[i])
[5185]273      {
274       addLength = i;
[5245]275//       break;
[5185]276      }
[5178]277    charElem = charIterator->nextElement();
278  }
279  delete charIterator;
[5245]280  PRINT(0)("\n");
[5178]281
282  if (addLength >= inputLenght)
283  {
284    char* adder = new char[addLength+1];
285    strncpy(adder, addString, addLength);
286    adder[addLength] = '\0';
287
[5182]288    if (this->input)
289    {
290     this->input->removeCharacters(inputLenght);
291     this->input->addCharacters(adder);
[5178]292
[5192]293      if (completionList->getSize() == 1)
[5185]294      {
295        if ( addBack != NULL )
296         this->input->addCharacters(addBack);
297        this->input->addCharacter(' ');
298      }
[5182]299     delete[] adder;
300    }
[5178]301  }
302  return true;
303}
304
305/**
[5187]306 * searches for classes, which beginn with completionBegin
[5178]307 * @param inputList the List to parse through
[5187]308 * @param completionBegin the beginning string
[5178]309 * !! The strings MUST NOT be deleted !!
310 */
[5245]311bool ShellCompletion::addToCompleteList(const tList<const char>* inputList, const char* completionBegin, SHELLC_TYPE type)
[5178]312{
[5187]313  if (inputList == NULL || completionBegin == NULL)
[5192]314    return false;
[5187]315  unsigned int searchLength = strlen(completionBegin);
[5178]316
317  tIterator<const char>* iterator = inputList->getIterator();
318  const char* enumString = iterator->firstElement();
319  while (enumString != NULL)
320  {
[5185]321    if (strlen(enumString) >= searchLength &&
[5187]322        !strncasecmp(enumString, completionBegin, searchLength))
[5178]323    {
[5185]324      printf("%s\n", enumString);
[5187]325      ShellC_Element* newElem = new ShellC_Element;
326      newElem->name = enumString;
[5245]327      newElem->type = type;
[5187]328      this->completionList->add(newElem);
[5178]329    }
330    enumString = iterator->nextElement();
331  }
332  delete iterator;
333
[5192]334  return true;
[5178]335}
336
337/**
[5187]338 * searches for classes, which beginn with completionBegin
[5178]339 * @param inputList the List to parse through
[5187]340 * @param completionBegin the beginning string
[5178]341 * !! The strings MUST NOT be deleted !!
342 */
[5245]343bool ShellCompletion::addToCompleteList(const tList<BaseObject>* inputList, const char* completionBegin, SHELLC_TYPE type)
[5178]344{
[5187]345  if (inputList == NULL || completionBegin == NULL)
[5192]346    return false;
[5187]347  unsigned int searchLength = strlen(completionBegin);
[5178]348
349  tIterator<BaseObject>* iterator = inputList->getIterator();
350  BaseObject* enumBO = iterator->firstElement();
351  while (enumBO != NULL)
352  {
353    if (enumBO->getName() != NULL &&
[5185]354        strlen(enumBO->getName()) >= searchLength &&
[5187]355        !strncasecmp(enumBO->getName(), completionBegin, searchLength))
[5178]356    {
[5187]357      ShellC_Element* newElem = new ShellC_Element;
358      newElem->name = enumBO->getName();
[5245]359      newElem->type = type;
[5187]360      this->completionList->add(newElem);
[5178]361    }
362    enumBO = iterator->nextElement();
363  }
364  delete iterator;
365
[5192]366  return true;
[5178]367}
[5187]368
[5197]369/**
370 * deletes the Completion List.
371 *
372 * This is done at the beginning of each completion-run
373 */
[5187]374void ShellCompletion::emptyCompletionList()
375{
376  if (this->completionList != NULL)
377  {
378    tIterator<ShellC_Element>* elemIT = this->completionList->getIterator();
379    ShellC_Element* elem = elemIT->firstElement();
380    while (elem != NULL)
381    {
382      delete elem;
383      elem = elemIT->nextElement();
384    }
385    delete this->completionList;
386  }
387  this->completionList = new tList<ShellC_Element>;
388}
[5245]389
390const char* ShellCompletion::typeToString(SHELLC_TYPE type)
391{
392  switch (type)
393  {
394    default:// SHELLC_NONE
395      return "error";
396    case  SHELLC_CLASS:
397      return "class";
398    case SHELLC_OBJECT:
399      return "object";
400    case SHELLC_FUNCTION:
401      return "function";
402    case SHELLC_ALIAS:
403      return "alias";
404  }
405}
Note: See TracBrowser for help on using the repository browser.