+}\r
+\r
+/**\r
+ Print at a specific location on the screen.\r
+\r
+ This function will move the cursor to a given screen location and print the specified string.\r
+\r
+ If -1 is specified for either the Row or Col the current screen location for BOTH\r
+ will be used.\r
+\r
+ If either Row or Col is out of range for the current console, then ASSERT.\r
+ If Format is NULL, then ASSERT.\r
+\r
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports\r
+ the following additional flags:\r
+ %N - Set output attribute to normal\r
+ %H - Set output attribute to highlight\r
+ %E - Set output attribute to error\r
+ %B - Set output attribute to blue color\r
+ %V - Set output attribute to green color\r
+\r
+ Note: The background color is controlled by the shell command cls.\r
+\r
+ @param[in] Row the row to print at\r
+ @param[in] Col the column to print at\r
+ @param[in] Format the format string\r
+\r
+ @return the number of characters printed to the screen\r
+**/\r
+\r
+UINTN\r
+EFIAPI\r
+ShellPrintEx(\r
+ IN INT32 Col OPTIONAL,\r
+ IN INT32 Row OPTIONAL,\r
+ IN CONST CHAR16 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ EFI_STATUS Status;\r
+ VA_START (Marker, Format);\r
+ Status = InternalShellPrintWorker(Col, Row, Format, Marker);\r
+ VA_END(Marker);\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Print at a specific location on the screen.\r
+\r
+ This function will move the cursor to a given screen location and print the specified string.\r
+\r
+ If -1 is specified for either the Row or Col the current screen location for BOTH\r
+ will be used.\r
+\r
+ If either Row or Col is out of range for the current console, then ASSERT.\r
+ If Format is NULL, then ASSERT.\r
+\r
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports\r
+ the following additional flags:\r
+ %N - Set output attribute to normal.\r
+ %H - Set output attribute to highlight.\r
+ %E - Set output attribute to error.\r
+ %B - Set output attribute to blue color.\r
+ %V - Set output attribute to green color.\r
+\r
+ Note: The background color is controlled by the shell command cls.\r
+\r
+ @param[in] Row The row to print at.\r
+ @param[in] Col The column to print at.\r
+ @param[in] Language The language of the string to retrieve. If this parameter\r
+ is NULL, then the current platform language is used.\r
+ @param[in] HiiFormatStringId The format string Id for getting from Hii.\r
+ @param[in] HiiFormatHandle The format string Handle for getting from Hii.\r
+\r
+ @return the number of characters printed to the screen.\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellPrintHiiEx(\r
+ IN INT32 Col OPTIONAL,\r
+ IN INT32 Row OPTIONAL,\r
+ IN CONST CHAR8 *Language OPTIONAL,\r
+ IN CONST EFI_STRING_ID HiiFormatStringId,\r
+ IN CONST EFI_HANDLE HiiFormatHandle,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ CHAR16 *HiiFormatString;\r
+ UINTN RetVal;\r
+\r
+ VA_START (Marker, HiiFormatHandle);\r
+ HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);\r
+ ASSERT(HiiFormatString != NULL);\r
+\r
+ RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);\r
+\r
+ FreePool(HiiFormatString);\r
+ VA_END(Marker);\r
+\r
+ return (RetVal);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file or a directory.\r
+\r
+ @param[in] DirName Path to directory to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a directory\r
+ @retval EFI_NOT_FOUND The Path does not represent a directory\r
+ @return other The path failed to open\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsDirectory(\r
+ IN CONST CHAR16 *DirName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE Handle;\r
+\r
+ ASSERT(DirName != NULL);\r
+\r
+ Handle = NULL;\r
+\r
+ Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file.\r
+\r
+ @param[in] Name Path to file to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a file.\r
+ @retval EFI_NOT_FOUND The Path does not represent a file.\r
+ @retval other The path failed to open.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsFile(\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE Handle;\r
+\r
+ ASSERT(Name != NULL);\r
+\r
+ Handle = NULL;\r
+\r
+ Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file.\r
+\r
+ This will search the CWD and then the Path.\r
+\r
+ If Name is NULL, then ASSERT.\r
+\r
+ @param[in] Name Path to file to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a file.\r
+ @retval EFI_NOT_FOUND The Path does not represent a file.\r
+ @retval other The path failed to open.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsFileInPath(\r
+ IN CONST CHAR16 *Name\r
+ ) {\r
+ CHAR16 *NewName;\r
+ EFI_STATUS Status;\r
+\r
+ if (!EFI_ERROR(ShellIsFile(Name))) {\r
+ return (TRUE);\r
+ }\r
+\r
+ NewName = ShellFindFilePath(Name);\r
+ if (NewName == NULL) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+ Status = ShellIsFile(NewName);\r
+ FreePool(NewName);\r
+ return (Status);\r
+}\r
+/**\r
+ Function to determine whether a string is decimal or hex representation of a number\r
+ and return the number converted from the string.\r
+\r
+ @param[in] String String representation of a number\r
+\r
+ @retval all the number\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellStrToUintn(\r
+ IN CONST CHAR16 *String\r
+ )\r
+{\r
+ CONST CHAR16 *Walker;\r
+ for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);\r
+ if (Walker == NULL || *Walker == CHAR_NULL) {\r
+ ASSERT(FALSE);\r
+ return ((UINTN)(-1));\r
+ } else {\r
+ if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){\r
+ return (StrHexToUintn(Walker));\r
+ }\r
+ return (StrDecimalToUintn(Walker));\r
+ }\r
+}\r
+\r
+/**\r
+ Safely append with automatic string resizing given length of Destination and\r
+ desired length of copy from Source.\r
+\r
+ append the first D characters of Source to the end of Destination, where D is\r
+ the lesser of Count and the StrLen() of Source. If appending those D characters\r
+ will fit within Destination (whose Size is given as CurrentSize) and\r
+ still leave room for a NULL terminator, then those characters are appended,\r
+ starting at the original terminating NULL of Destination, and a new terminating\r
+ NULL is appended.\r
+\r
+ If appending D characters onto Destination will result in a overflow of the size\r
+ given in CurrentSize the string will be grown such that the copy can be performed\r
+ and CurrentSize will be updated to the new size.\r
+\r
+ If Source is NULL, there is nothing to append, just return the current buffer in\r
+ Destination.\r
+\r
+ if Destination is NULL, then ASSERT()\r
+ if Destination's current length (including NULL terminator) is already more then\r
+ CurrentSize, then ASSERT()\r
+\r
+ @param[in,out] Destination The String to append onto\r
+ @param[in,out] CurrentSize on call the number of bytes in Destination. On\r
+ return possibly the new size (still in bytes). if NULL\r
+ then allocate whatever is needed.\r
+ @param[in] Source The String to append from\r
+ @param[in] Count Maximum number of characters to append. if 0 then\r
+ all are appended.\r
+\r
+ @return Destination return the resultant string.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+StrnCatGrow (\r
+ IN OUT CHAR16 **Destination,\r
+ IN OUT UINTN *CurrentSize,\r
+ IN CONST CHAR16 *Source,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ UINTN DestinationStartSize;\r
+ UINTN NewSize;\r
+\r
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT(Destination != NULL);\r
+\r
+ //\r
+ // If there's nothing to do then just return Destination\r
+ //\r
+ if (Source == NULL) {\r
+ return (*Destination);\r
+ }\r
+\r
+ //\r
+ // allow for un-initialized pointers, based on size being 0\r
+ //\r
+ if (CurrentSize != NULL && *CurrentSize == 0) {\r
+ *Destination = NULL;\r
+ }\r
+\r
+ //\r
+ // allow for NULL pointers address as Destination\r
+ //\r
+ if (*Destination != NULL) {\r
+ ASSERT(CurrentSize != 0);\r
+ DestinationStartSize = StrSize(*Destination);\r
+ ASSERT(DestinationStartSize <= *CurrentSize);\r
+ } else {\r
+ DestinationStartSize = 0;\r
+// ASSERT(*CurrentSize == 0);\r
+ }\r
+\r
+ //\r
+ // Append all of Source?\r
+ //\r
+ if (Count == 0) {\r
+ Count = StrLen(Source);\r
+ }\r
+\r
+ //\r
+ // Test and grow if required\r
+ //\r
+ if (CurrentSize != NULL) {\r
+ NewSize = *CurrentSize;\r
+ while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {\r
+ NewSize += 2 * Count * sizeof(CHAR16);\r
+ }\r
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+ *CurrentSize = NewSize;\r
+ } else {\r
+ *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));\r
+ }\r
+\r
+ //\r
+ // Now use standard StrnCat on a big enough buffer\r
+ //\r
+ return StrnCat(*Destination, Source, Count);\r
+}\r