Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: classList: returns const lists

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