+/**\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[in, out] TabCompletionList Return the TAB completion list.\r
+ @param[in, out] TabUpdatePos Return the TAB update position.\r
+**/\r
+EFI_STATUS\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 ":", ...\r
+ //\r
+ Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);\r
+ if (Cwd != NULL) {\r
+ if (InputString[TabPos] != L'\\') {\r
+ //\r
+ // and it doesn't begin with "\\", it's a path relative to current directory.\r
+ // TabStr = "<cwd>\\"\r
+ //\r
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);\r
+ StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");\r
+ } else {\r
+ //\r
+ // and it begins with "\\", it's a path pointing to root directory of current map.\r
+ // TabStr = "fsx:"\r
+ //\r
+ Index = StrStr (Cwd, L":") - Cwd + 1;\r
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);\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