Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: shell now also autocompletes Commands

File size: 9.7 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: ...
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell_completion.h"
19
20#include "shell_input.h"
21#include "shell_command.h"
22
23#include "substring.h"
24#include "base_object.h"
25#include "class_list.h"
26#include "list.h"
27#include "debug.h"
28
29#include "stdlibincl.h"
30
31using namespace std;
32
33/**
34 * standard constructor
35 * @todo this constructor is not jet implemented - do it
36*/
37ShellCompletion::ShellCompletion(ShellInput* input)
38{
39  this->completionList = NULL;
40  this->input = input;
41}
42
43
44/**
45 * standard deconstructor
46*/
47ShellCompletion::~ShellCompletion ()
48{
49  // delete what has to be deleted here
50  if (this->completionList)
51  {
52    this->emptyCompletionList();
53    delete this->completionList;
54  }
55}
56
57
58
59/**
60 * autocompletes the Shell's inputLine
61 * @returns true, if a result was found, false otherwise
62 *
63 * @todo implement it!!
64 */
65bool ShellCompletion::autoComplete(ShellInput* input)
66{
67  const char* completionLine;      //< the inputLine we complete.
68
69  long classID;                    //< the classID retrieved from the Class.
70  tList<BaseObject>* objectList;   //< the list of Objects stored in classID
71  bool emptyComplete = false;      //< if the completion input is empty string. e.g ""
72  long completeType = SHELLC_NONE; //< the Type we'd like to complete.
73  const char* completeString;      //< the string to complete.
74
75
76  PRINTF(5)("AutoComplete on input\n");
77  this->emptyCompletionList();
78
79  if (input != NULL)
80    this->input = input;
81  if (this->input == NULL)
82  {
83    PRINTF(2)("No ShellInput supplied\n");
84    return false;
85  }
86
87  // Check if we are in a input. eg. the supplied string "class " and now we complete either function or object
88  if (this->input->getInput() != NULL &&
89      strrchr(this->input->getInput(), ' ') >= this->input->getInput() + strlen(this->input->getInput())-1)
90  {
91    emptyComplete = true;
92  }
93
94  // CREATE INPUTS
95  if (this->input->getInput() == NULL)
96    completionLine = "";
97  else
98    completionLine = this->input->getInput() + strspn(this->input->getInput(), " \t\n");
99  SubString inputSplits(completionLine, true);
100
101  // What String will be completed
102  if (emptyComplete == true)
103    completeString = "";
104  else
105    completeString = inputSplits.getString(inputSplits.getCount()-1);
106
107  // CLASS COMPLETION
108  if (inputSplits.getCount() == 0)
109  {
110    PRINTF(5)("Listing all Classes\n");
111    completeType |= SHELLC_CLASS;
112  }
113  else if (inputSplits.getCount() == 1 && emptyComplete == false)
114  {
115    printf("trying to complete a Class with '%s'\n", inputSplits.getString(0));
116    completeType |= SHELLC_CLASS;
117  }
118
119  // OBJECT/FUNCTION COMPLETIONS
120  else if ((inputSplits.getCount() == 1 && emptyComplete == true) ||
121            (inputSplits.getCount() == 2 && emptyComplete == false))
122  {
123    classID = ClassList::StringToID(inputSplits.getString(0));
124    objectList = ClassList::getList(classID);
125    if (classID == CL_NULL)
126      return false;
127    else
128    {
129      if (objectList != NULL && objectList->getSize() == 1)
130        completeType |= SHELLC_FUNCTION;
131      completeType |= SHELLC_OBJECT;
132    }
133  }
134  else if ((inputSplits.getCount() == 2 && emptyComplete == true) ||
135            (inputSplits.getCount() == 3 && emptyComplete == false))
136  {
137    classID = ClassList::StringToID(inputSplits.getString(0));
138    if (classID == CL_NULL)
139      return false;
140    else
141     completeType |= SHELLC_FUNCTION;
142  }
143
144  if (completeType & SHELLC_CLASS)
145    this->objectComplete(completeString, CL_SHELL_COMMAND_CLASS);
146  if (completeType & SHELLC_OBJECT)
147    this->objectComplete(completeString, classID);
148  if (completeType & SHELLC_FUNCTION)
149    this->functionComplete(completeString, classID);
150
151
152  this->generalComplete(completeString);
153  return true;
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  {
168    if (!this->addToCompleteList(clList, classBegin))
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;
186  const tList<BaseObject>* boList = ClassList::getList(classID);
187  if (boList != NULL)
188  {
189    //printf("%s\n", boList->firstElement()->getName());
190    if (!this->addToCompleteList(boList, objectBegin))
191      return false;
192  }
193  else
194    return false;
195  return true;
196}
197
198/**
199 * completes a Function
200 * @param functionBegin the beginning of the function String
201 */
202bool ShellCompletion::functionComplete(const char* functionBegin, long classID)
203{
204  if (unlikely(functionBegin == NULL))
205    return false;
206  tList<const char> fktList;
207  ShellCommandClass::getCommandListOfClass(ClassList::IDToString(classID), &fktList);
208  //printf("%s\n", boList->firstElement()->getName());
209  if (!this->addToCompleteList(&fktList, functionBegin))
210    return false;
211  return true;
212}
213
214/**
215 * completes the inputline on grounds of an inputList
216 * @param begin the String to search in the inputList, and to extend with it.
217 * @param displayAs how to display the found value to the user, printf-style, !!with only one %s!! ex.: "::%s::"
218 * @param addBack what should be added at the end of the completion
219 * @param addFront what should be added to the front of one finished completion
220 * @return true if ok, false otherwise
221 */
222bool ShellCompletion::generalComplete(const char* begin, const char* displayAs, const char* addBack, const char* addFront)
223{
224  if (completionList == NULL || this->input == NULL )
225    return false;
226  if (completionList->getSize() == 0)
227    return false;
228
229  ShellC_Element* addElem = completionList->firstElement();
230  const char* addString = addElem->name;
231  unsigned int addLength = 0;
232  unsigned int inputLenght = strlen(begin);
233
234  // Determin the longest Match
235  if (addString != NULL)
236    addLength = strlen(addString);
237  tIterator<ShellC_Element>* charIterator = completionList->getIterator();
238  ShellC_Element* charElem = charIterator->firstElement();
239  while (charElem != NULL)
240  {
241    PRINTF(0)(displayAs, charElem->name);
242    for (unsigned int i = inputLenght; i < addLength; i++)
243      if (addString[i] != charElem->name[i])
244      {
245       addLength = i;
246       break;
247      }
248    charElem = charIterator->nextElement();
249  }
250  delete charIterator;
251
252  if (addLength >= inputLenght)
253  {
254    char* adder = new char[addLength+1];
255    strncpy(adder, addString, addLength);
256    adder[addLength] = '\0';
257
258    if (this->input)
259    {
260     this->input->removeCharacters(inputLenght);
261     this->input->addCharacters(adder);
262
263      if (completionList->getSize() == 1)
264      {
265        if ( addBack != NULL )
266         this->input->addCharacters(addBack);
267        this->input->addCharacter(' ');
268      }
269     delete[] adder;
270    }
271  }
272  return true;
273}
274
275/**
276 * searches for classes, which beginn with completionBegin
277 * @param inputList the List to parse through
278 * @param completionBegin the beginning string
279 * !! The strings MUST NOT be deleted !!
280 */
281bool ShellCompletion::addToCompleteList(const tList<const char>* inputList, const char* completionBegin)
282{
283  if (inputList == NULL || completionBegin == NULL)
284    return false;
285  unsigned int searchLength = strlen(completionBegin);
286
287  tIterator<const char>* iterator = inputList->getIterator();
288  const char* enumString = iterator->firstElement();
289  while (enumString != NULL)
290  {
291    if (strlen(enumString) >= searchLength &&
292        !strncasecmp(enumString, completionBegin, searchLength))
293    {
294      printf("%s\n", enumString);
295      ShellC_Element* newElem = new ShellC_Element;
296      newElem->name = enumString;
297      this->completionList->add(newElem);
298    }
299    enumString = iterator->nextElement();
300  }
301  delete iterator;
302
303  return true;
304}
305
306/**
307 * searches for classes, which beginn with completionBegin
308 * @param inputList the List to parse through
309 * @param completionBegin the beginning string
310 * !! The strings MUST NOT be deleted !!
311 */
312bool ShellCompletion::addToCompleteList(const tList<BaseObject>* inputList, const char* completionBegin)
313{
314  if (inputList == NULL || completionBegin == NULL)
315    return false;
316  unsigned int searchLength = strlen(completionBegin);
317
318  tIterator<BaseObject>* iterator = inputList->getIterator();
319  BaseObject* enumBO = iterator->firstElement();
320  while (enumBO != NULL)
321  {
322    if (enumBO->getName() != NULL &&
323        strlen(enumBO->getName()) >= searchLength &&
324        !strncasecmp(enumBO->getName(), completionBegin, searchLength))
325    {
326      ShellC_Element* newElem = new ShellC_Element;
327      newElem->name = enumBO->getName();
328      this->completionList->add(newElem);
329      printf("%s\n",enumBO->getName());
330    }
331    enumBO = iterator->nextElement();
332  }
333  delete iterator;
334
335  return true;
336}
337
338
339void ShellCompletion::emptyCompletionList()
340{
341  if (this->completionList != NULL)
342  {
343    tIterator<ShellC_Element>* elemIT = this->completionList->getIterator();
344    ShellC_Element* elem = elemIT->firstElement();
345    while (elem != NULL)
346    {
347      delete elem;
348      elem = elemIT->nextElement();
349    }
350    delete this->completionList;
351  }
352  this->completionList = new tList<ShellC_Element>;
353}
Note: See TracBrowser for help on using the repository browser.