return (EFI_SUCCESS);\r
}\r
\r
+/**\r
+ Create the TAB completion list.\r
+\r
+ @param[in] InputString The command line to expand.\r
+ @param[in] StringLen Length of the command line.\r
+ @param[in] BufferSize Buffer size.\r
+ @param[out] TabCompletionList Return the TAB completion list.\r
+ @param[out] TabUpdatePos Return the TAB update position.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreateTabCompletionList (\r
+ IN CONST CHAR16 *InputString,\r
+ IN CONST UINTN StringLen, \r
+ IN CONST UINTN BufferSize,\r
+ IN OUT EFI_SHELL_FILE_INFO **TabCompletionList,\r
+ IN OUT UINTN *TabUpdatePos\r
+)\r
+{\r
+ BOOLEAN InQuotation;\r
+ UINTN TabPos;\r
+ UINTN Index;\r
+ CONST CHAR16 *Cwd;\r
+ EFI_STATUS Status;\r
+ CHAR16 *TabStr;\r
+ EFI_SHELL_FILE_INFO *FileList;\r
+ EFI_SHELL_FILE_INFO *FileInfo;\r
+ EFI_SHELL_FILE_INFO *TempFileInfo;\r
+\r
+ //\r
+ // Allocate buffers\r
+ //\r
+ TabStr = AllocateZeroPool (BufferSize);\r
+ if (TabStr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // handle auto complete of file and directory names...\r
+ // E.g.: cd fs0:\EFI\Bo<TAB>\r
+ // ^ ^\r
+ // TabPos TabUpdatePos\r
+ //\r
+ TabPos = 0;\r
+ *TabUpdatePos = 0;\r
+ FileList = NULL;\r
+ InQuotation = FALSE;\r
+ for (Index = 0; Index < StringLen; Index++) {\r
+ switch (InputString[Index]) {\r
+ case L'\"':\r
+ InQuotation = (BOOLEAN) (!InQuotation);\r
+ break;\r
+\r
+ case L' ':\r
+ if (!InQuotation) {\r
+ TabPos = Index + 1;\r
+ *TabUpdatePos = TabPos;\r
+ }\r
+ break;\r
+\r
+ case L':':\r
+ //\r
+ // handle the case "fs0:<TAB>"\r
+ // Update the TabUpdatePos as well.\r
+ //\r
+ case L'\\':\r
+ *TabUpdatePos = Index + 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (StrStr (InputString + TabPos, L":") == NULL) {\r
+ //\r
+ // If file path doesn't contain ":", it's a path relative to current directory.\r
+ //\r
+ Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);\r
+ if (Cwd != NULL) {\r
+ StrnCpyS (TabStr, (BufferSize) / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);\r
+ if (InputString[TabPos] != L'\\') {\r
+ StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");\r
+ }\r
+ }\r
+ }\r
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);\r
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));\r
+ Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);\r
+\r
+ //\r
+ // Filter out the non-directory for "CD" command\r
+ // Filter "." and ".." for all\r
+ //\r
+ if (!EFI_ERROR (Status) && FileList != NULL) {\r
+ //\r
+ // Skip the spaces in the beginning\r
+ //\r
+ while (*InputString == L' ') {\r
+ InputString++;\r
+ }\r
+\r
+ for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {\r
+ if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||\r
+ (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&\r
+ (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {\r
+ TempFileInfo = FileInfo;\r
+ FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);\r
+ InternalFreeShellFileInfoNode (TempFileInfo);\r
+ } else {\r
+ FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (FileList != NULL && !IsListEmpty (&FileList->Link)) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ FreePool (TabStr);\r
+\r
+ *TabCompletionList = FileList;\r
+ return Status;\r
+}\r
+\r
/**\r
File style interface for console (Read).\r
\r
{\r
CHAR16 *CurrentString;\r
BOOLEAN Done;\r
+ UINTN TabUpdatePos; // Start index of the string updated by TAB stroke\r
UINTN Column; // Column of current cursor\r
UINTN Row; // Row of current cursor\r
UINTN StartColumn; // Column at the beginning of the line\r
UINTN StringLen; // Total length of the line\r
UINTN StringCurPos; // Line index corresponding to the cursor\r
UINTN MaxStr; // Maximum possible line length\r
- UINTN Index;\r
UINTN TotalColumn; // Num of columns in the console\r
UINTN TotalRow; // Num of rows in the console\r
UINTN SkipLength;\r
BOOLEAN InScrolling;\r
EFI_STATUS Status;\r
BOOLEAN InTabScrolling; // Whether in TAB-completion state\r
- EFI_SHELL_FILE_INFO *FoundFileList;\r
- EFI_SHELL_FILE_INFO *TabLinePos;\r
- EFI_SHELL_FILE_INFO *TempPos;\r
- CHAR16 *TabStr;\r
- CHAR16 *TabOutputStr;\r
- BOOLEAN InQuotationMode;\r
- CHAR16 *TempStr;\r
- UINTN TabPos; // Start index of the string to search for TAB completion.\r
- UINTN TabUpdatePos; // Start index of the string updated by TAB stroke\r
-// UINTN Count;\r
+ EFI_SHELL_FILE_INFO *TabCompleteList;\r
+ EFI_SHELL_FILE_INFO *TabCurrent;\r
UINTN EventIndex;\r
- CONST CHAR16 *Cwd;\r
+ CHAR16 *TabOutputStr;\r
\r
//\r
// If buffer is not large enough to hold a CHAR16, return minimum buffer size\r
InScrolling = FALSE;\r
InTabScrolling = FALSE;\r
Status = EFI_SUCCESS;\r
- TabLinePos = NULL;\r
- FoundFileList = NULL;\r
- TempPos = NULL;\r
- TabPos = 0;\r
+ TabOutputStr = NULL;\r
TabUpdatePos = 0;\r
-\r
- //\r
- // Allocate buffers\r
- //\r
- TabStr = AllocateZeroPool (*BufferSize);\r
- if (TabStr == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- TabOutputStr = AllocateZeroPool (*BufferSize);\r
- if (TabOutputStr == NULL) {\r
- FreePool(TabStr);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ TabCompleteList = NULL;\r
+ TabCurrent = NULL;\r
\r
//\r
// Get the screen setting and the current cursor location\r
// If we are quitting TAB scrolling...\r
//\r
if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {\r
- if (FoundFileList != NULL) {\r
- ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
- DEBUG_CODE(FoundFileList = NULL;);\r
- }\r
- InTabScrolling = FALSE;\r
+ if (TabCompleteList != NULL) {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
+ DEBUG_CODE(TabCompleteList = NULL;);\r
+ }\r
+ InTabScrolling = FALSE;\r
}\r
\r
switch (Key.UnicodeChar) {\r
break;\r
\r
case CHAR_TAB:\r
- //\r
- // handle auto complete of file and directory names...\r
- //\r
- if (InTabScrolling) {\r
- ASSERT(FoundFileList != NULL);\r
- ASSERT(TabLinePos != NULL);\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
- if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) {\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
- }\r
- } else {\r
- TabPos = 0;\r
- TabUpdatePos = 0;\r
- InQuotationMode = FALSE;\r
- for (Index = 0; Index < StringLen; Index++) {\r
- if (CurrentString[Index] == L'\"') {\r
- InQuotationMode = (BOOLEAN)(!InQuotationMode);\r
- }\r
- if (CurrentString[Index] == L' ' && !InQuotationMode) {\r
- TabPos = Index + 1;\r
- TabUpdatePos = Index + 1;\r
- }\r
- if (CurrentString[Index] == L'\\') {\r
- TabUpdatePos = Index + 1;\r
- }\r
+ if (!InTabScrolling) {\r
+ TabCurrent = NULL;\r
+ //\r
+ // Initialize a tab complete operation.\r
+ //\r
+ Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);\r
+ if (!EFI_ERROR(Status)) {\r
+ InTabScrolling = TRUE;\r
}\r
- if (StrStr(CurrentString + TabPos, L":") == NULL) {\r
- Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL);\r
- if (Cwd != NULL) {\r
- StrnCpyS(TabStr, (*BufferSize)/sizeof(CHAR16), Cwd, (*BufferSize)/sizeof(CHAR16) - 1);\r
- StrCatS(TabStr, (*BufferSize)/sizeof(CHAR16), L"\\");\r
- if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {\r
- TabStr[StrLen(TabStr)-1] = CHAR_NULL;\r
- }\r
- StrnCatS( TabStr, \r
- (*BufferSize)/sizeof(CHAR16), \r
- CurrentString + TabPos, \r
- StringLen - TabPos\r
- );\r
- } else {\r
- *TabStr = CHAR_NULL;\r
- StrnCatS(TabStr, (*BufferSize)/sizeof(CHAR16), CurrentString + TabPos, StringLen - TabPos);\r
- }\r
+\r
+ //\r
+ // We do not set up the replacement.\r
+ // The next section will do that.\r
+ //\r
+ }\r
+\r
+ if (InTabScrolling) {\r
+ //\r
+ // We are in a tab complete operation.\r
+ // set up the next replacement.\r
+ //\r
+ ASSERT(TabCompleteList != NULL);\r
+ if (TabCurrent == NULL) {\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);\r
} else {\r
- StrnCpyS(TabStr, (*BufferSize)/sizeof(CHAR16), CurrentString + TabPos, (*BufferSize)/sizeof(CHAR16) - 1);\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
}\r
- StrnCatS(TabStr, (*BufferSize)/sizeof(CHAR16), L"*", (*BufferSize)/sizeof(CHAR16) - 1 - StrLen(TabStr));\r
- FoundFileList = NULL;\r
- Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);\r
- for ( TempStr = CurrentString\r
- ; *TempStr == L' '\r
- ; TempStr++); // note the ';'... empty for loop\r
+\r
//\r
- // make sure we have a list before we do anything more...\r
+ // Skip over the empty list beginning node\r
//\r
- if (EFI_ERROR (Status) || FoundFileList == NULL) {\r
- InTabScrolling = FALSE;\r
- TabLinePos = NULL;\r
- continue;\r
- } else {\r
- //\r
- // enumerate through the list of files\r
- //\r
- for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))\r
- ; !IsNull(&FoundFileList->Link, &TempPos->Link)\r
- ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))\r
- ){\r
- //\r
- // If "cd" is typed, only directory name will be auto-complete filled\r
- // in either case . and .. will be removed.\r
- //\r
- if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&\r
- (TempStr[1] == L'd' || TempStr[1] == L'D')\r
- ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)\r
- ||(StrCmp(TempPos->FileName, L".") == 0)\r
- ||(StrCmp(TempPos->FileName, L"..") == 0)\r
- )) || ((StrCmp(TempPos->FileName, L".") == 0)\r
- ||(StrCmp(TempPos->FileName, L"..") == 0))){\r
- TabLinePos = TempPos;\r
- TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);\r
- InternalFreeShellFileInfoNode(TabLinePos);\r
- }\r
- }\r
- if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);\r
- InTabScrolling = TRUE;\r
- } else {\r
- ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
- }\r
+ if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
}\r
}\r
break;\r
// the next file or directory name\r
//\r
if (InTabScrolling) {\r
+ TabOutputStr = AllocateZeroPool (*BufferSize);\r
+ if (TabOutputStr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ if (InTabScrolling && TabOutputStr != NULL) {\r
+\r
//\r
// Adjust the column and row to the start of TAB-completion string.\r
//\r
Column = (StartColumn + TabUpdatePos) % TotalColumn;\r
Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;\r
- OutputLength = StrLen (TabLinePos->FileName);\r
+ OutputLength = StrLen (TabCurrent->FileName);\r
//\r
// if the output string contains blank space, quotation marks L'\"'\r
// should be added to the output.\r
//\r
- if (StrStr(TabLinePos->FileName, L" ") != NULL){\r
+ if (StrStr(TabCurrent->FileName, L" ") != NULL){\r
TabOutputStr[0] = L'\"';\r
- CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+ CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
TabOutputStr[OutputLength + 1] = L'\"';\r
TabOutputStr[OutputLength + 2] = CHAR_NULL;\r
} else {\r
- CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+ CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
TabOutputStr[OutputLength] = CHAR_NULL;\r
}\r
OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;\r
if (StringLen > TabUpdatePos + OutputLength) {\r
Delete = StringLen - TabUpdatePos - OutputLength;\r
}\r
+\r
+ FreePool(TabOutputStr);\r
}\r
\r
//\r
AddLineToCommandHistory(CurrentString);\r
}\r
\r
- FreePool (TabStr);\r
- FreePool (TabOutputStr);\r
//\r
// Return the data to the caller\r
//\r
// if this was used it should be deallocated by now...\r
// prevent memory leaks...\r
//\r
- if (FoundFileList != NULL) {\r
- ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
+ if (TabCompleteList != NULL) {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
}\r
- ASSERT(FoundFileList == NULL);\r
+ ASSERT(TabCompleteList == NULL);\r
\r
return Status;\r
}\r