Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: merged the std-branche back, it runs on windows and Linux

svn merge https://svn.orxonox.net/orxonox/branches/std . -r7202:HEAD

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