Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: executing static commands work

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