Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/guidedmissile/src/lib/shell/shell_completion.cc @ 5758

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

orxonox/trunk: new Version of the String-splitter (without Escape-sequence for the time being)

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