You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2160 lines
44 KiB
2160 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arcdisp.c
|
|
|
|
Abstract:
|
|
|
|
This module provides code for managing screen output on an ARC-compliant
|
|
system.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 6-Oct-1993
|
|
|
|
Revision History:
|
|
|
|
John Vert (jvert) 6-Oct-1993
|
|
Taken from old 1.0 splib sources
|
|
|
|
--*/
|
|
#include "setupldr.h"
|
|
#include "parseini.h"
|
|
#include "stdio.h"
|
|
#include "hdlsterm.h"
|
|
|
|
#ifdef i386
|
|
#include "bldrx86.h"
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
#include "bldria64.h"
|
|
#endif
|
|
|
|
#if defined(EFI)
|
|
#include "bootefi.h"
|
|
#endif
|
|
|
|
|
|
//
|
|
// The screen is divided into 3 areas: the header area, the status area,
|
|
// and the client area. The header area basically always says "Windows NT
|
|
// Setup". The status area is always 1 line high and displayed using a
|
|
// different attribute (black on gray).
|
|
//
|
|
|
|
|
|
#define HEADER_HEIGHT 3
|
|
#define MAX_STATUS 200 // allow up to 1600 horizontal res.
|
|
|
|
#define SCREEN_SIZE (ScreenWidth*ScreenHeight)
|
|
|
|
BOOLEAN StatusBarEnabled = TRUE;
|
|
ULONG ScreenWidth=80;
|
|
ULONG ScreenHeight=25;
|
|
ULONG ScreenX=0,ScreenY=0;
|
|
UCHAR CurAttribute = (ATT_FG_WHITE | ATT_BG_BLACK);
|
|
TCHAR MessageBuffer[1024];
|
|
|
|
extern BOOLEAN ShowProgressBar;
|
|
|
|
//
|
|
// private function prototypes
|
|
//
|
|
VOID
|
|
SlpDrawMenu(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG TopItem,
|
|
IN ULONG Height,
|
|
IN PSL_MENU Menu
|
|
);
|
|
|
|
VOID
|
|
SlpDrawMenuItem(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG TopItem,
|
|
IN ULONG Item,
|
|
IN PSL_MENU Menu
|
|
);
|
|
|
|
VOID
|
|
SlpSizeMessage(
|
|
IN PTCHAR Message,
|
|
OUT PULONG Lines,
|
|
OUT PULONG MaxLength,
|
|
OUT ULONG LineLength[],
|
|
OUT PTCHAR LineText[]
|
|
);
|
|
|
|
|
|
|
|
PSL_MENU
|
|
SlCreateMenu(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and initializes a new menu structure.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new menu structure if successful.
|
|
|
|
NULL on failure
|
|
|
|
--*/
|
|
{
|
|
PSL_MENU p;
|
|
|
|
p=BlAllocateHeap(sizeof(SL_MENU));
|
|
if (p==NULL) {
|
|
return(NULL);
|
|
}
|
|
p->ItemCount = 0;
|
|
p->Width = 0;
|
|
InitializeListHead(&p->ItemListHead);
|
|
return(p);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlGetMenuItemIndex(
|
|
IN PSL_MENU Menu,
|
|
IN PTCHAR Text,
|
|
OUT PULONG Index
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given the text of a menu item, returns the index of that item.
|
|
|
|
Arguments:
|
|
|
|
Menu - Supplies the menu
|
|
|
|
Text - Supplies the text to search for.
|
|
|
|
Index - Returns the index of the text in the menu
|
|
|
|
Return Value:
|
|
|
|
TRUE - Item was found.
|
|
|
|
FALSE - Item was not found
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PSL_MENUITEM Item;
|
|
|
|
//
|
|
// Find first item to display
|
|
//
|
|
Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
i=0;
|
|
while ( Item != CONTAINING_RECORD(&Menu->ItemListHead,
|
|
SL_MENUITEM,
|
|
ListEntry)) {
|
|
if (_tcsicmp(Item->Text,Text)==0) {
|
|
*Index = i;
|
|
return(TRUE);
|
|
}
|
|
|
|
Item = CONTAINING_RECORD(Item->ListEntry.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
++i;
|
|
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
PVOID
|
|
SlGetMenuItem(
|
|
IN PSL_MENU Menu,
|
|
IN ULONG Item
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an item index, returns the data associated with that item.
|
|
|
|
Arguments:
|
|
|
|
Menu - Supplies the menu structure.
|
|
|
|
Item - Supplies the item index.
|
|
|
|
Return Value:
|
|
|
|
The data associated with the given item.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PSL_MENUITEM MenuItem;
|
|
|
|
//
|
|
// Find item to return
|
|
//
|
|
MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
for (i=0;i<Item;i++) {
|
|
MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
#if DBG
|
|
if (&MenuItem->ListEntry == &Menu->ItemListHead) {
|
|
SlError(Item);
|
|
return(NULL);
|
|
}
|
|
#endif
|
|
}
|
|
return(MenuItem->Data);
|
|
|
|
}
|
|
|
|
|
|
ULONG
|
|
SlAddMenuItem(
|
|
PSL_MENU Menu,
|
|
PTCHAR Text,
|
|
PVOID Data,
|
|
ULONG Attributes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds an item to the menu
|
|
|
|
Arguments:
|
|
|
|
Menu - Supplies a pointer to the menu the item will be added to
|
|
|
|
Text - Supplies the text to be displayed in the menu
|
|
|
|
Data - Supplies a pointer to the data to be returned when the item
|
|
is selected.
|
|
|
|
Attributes - Supplies any attributes for the item.
|
|
|
|
Return Value:
|
|
|
|
The Selection index if successful
|
|
|
|
-1 on failure
|
|
|
|
--*/
|
|
{
|
|
PSL_MENUITEM NewItem;
|
|
ULONG Length;
|
|
|
|
NewItem = BlAllocateHeap(sizeof(SL_MENUITEM));
|
|
if (NewItem==NULL) {
|
|
SlError(0);
|
|
return((ULONG)-1);
|
|
}
|
|
InsertTailList(&Menu->ItemListHead, &NewItem->ListEntry);
|
|
Menu->ItemCount += 1;
|
|
|
|
NewItem->Text = Text;
|
|
NewItem->Data = Data;
|
|
NewItem->Attributes = Attributes;
|
|
Length = (ULONG)_tcslen(Text);
|
|
if (Length > Menu->Width) {
|
|
Menu->Width = Length;
|
|
}
|
|
return(Menu->ItemCount - 1);
|
|
}
|
|
|
|
|
|
ULONG
|
|
SlDisplayMenu(
|
|
IN ULONG HeaderId,
|
|
IN PSL_MENU Menu,
|
|
IN OUT PULONG Selection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays a menu and allows the user to pick a selection
|
|
|
|
Arguments:
|
|
|
|
HeaderId - Supplies the message ID of the prompt header
|
|
to be displayed above the menu.
|
|
|
|
Menu - Supplies a pointer to the menu to be displayed
|
|
|
|
Selection - Supplies the index of the default item.
|
|
Returns the index of the selected item.
|
|
|
|
Return Value:
|
|
|
|
Key that terminated the menu display.
|
|
|
|
--*/
|
|
{
|
|
LONG X, Y;
|
|
ULONG Height;
|
|
ULONG Width;
|
|
ULONG TopItem;
|
|
ULONG c;
|
|
ULONG PreviousSelection;
|
|
ULONG Sel;
|
|
PTCHAR Header;
|
|
ULONG HeaderLines;
|
|
ULONG MaxHeaderLength;
|
|
PTCHAR HeaderText[20];
|
|
ULONG HeaderLength[20];
|
|
ULONG MaxMenuHeight;
|
|
ULONG i;
|
|
ULONG Count;
|
|
|
|
Header = BlFindMessage(HeaderId);
|
|
|
|
SlpSizeMessage(Header,
|
|
&HeaderLines,
|
|
&MaxHeaderLength,
|
|
HeaderLength,
|
|
HeaderText);
|
|
|
|
if (MaxHeaderLength > ScreenWidth) {
|
|
MaxHeaderLength = ScreenWidth;
|
|
}
|
|
|
|
X = (ScreenWidth-MaxHeaderLength)/2;
|
|
for (i=0;i<HeaderLines;i++) {
|
|
SlPositionCursor(X,i+4);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,HeaderText[i],HeaderLength[i]*sizeof(TCHAR),&Count);
|
|
}
|
|
|
|
Width = Menu->Width+4;
|
|
if (Width > ScreenWidth) {
|
|
Width=ScreenWidth;
|
|
}
|
|
|
|
//
|
|
// HEADER_HEIGHT + 1 line separator + text height + 1 line separator + max menu heigth +
|
|
// + 1 line separator + 1 line status bar = screen height
|
|
//
|
|
MaxMenuHeight = ScreenHeight-(HeaderLines+HEADER_HEIGHT+4);
|
|
|
|
Height = Menu->ItemCount+2;
|
|
if (Height > MaxMenuHeight) {
|
|
Height = MaxMenuHeight;
|
|
}
|
|
|
|
X = (ScreenWidth-Width)/2;
|
|
Y = (MaxMenuHeight - Height)/2 + HeaderLines + HEADER_HEIGHT + 2;
|
|
|
|
TopItem = 0;
|
|
Sel = *Selection;
|
|
//
|
|
// Make sure default item is in view;
|
|
//
|
|
if (Sel >= Height - 2) {
|
|
TopItem = Sel - Height + 3;
|
|
}
|
|
|
|
SlpDrawMenu(X,Y,
|
|
TopItem,
|
|
Height,
|
|
Menu);
|
|
|
|
//
|
|
// highlight default selection
|
|
//
|
|
SlSetCurrentAttribute(INVATT);
|
|
SlpDrawMenuItem(X,Y,
|
|
TopItem,
|
|
Sel,
|
|
Menu);
|
|
SlSetCurrentAttribute(DEFATT);
|
|
SlFlushConsoleBuffer();
|
|
|
|
#ifdef EFI
|
|
//
|
|
// disable efi watchdog timer
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
do {
|
|
c = SlGetChar();
|
|
PreviousSelection = Sel;
|
|
SlpDrawMenuItem(X, Y,
|
|
TopItem,
|
|
Sel,
|
|
Menu);
|
|
|
|
switch (c) {
|
|
case SL_KEY_UP:
|
|
if(Sel > 0) {
|
|
Sel--;
|
|
}
|
|
break;
|
|
|
|
case SL_KEY_DOWN:
|
|
if(Sel < Menu->ItemCount - 1) {
|
|
Sel++;
|
|
}
|
|
break;
|
|
|
|
case SL_KEY_HOME:
|
|
Sel = 0;
|
|
break;
|
|
|
|
case SL_KEY_END:
|
|
Sel = Menu->ItemCount - 1;
|
|
break;
|
|
|
|
case SL_KEY_PAGEUP:
|
|
if (Menu->ItemCount > Height) {
|
|
if (Sel > Height) {
|
|
Sel -= Height;
|
|
} else {
|
|
Sel = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SL_KEY_PAGEDOWN:
|
|
if (Menu->ItemCount > Height) {
|
|
Sel += Height;
|
|
if (Sel >= Menu->ItemCount) {
|
|
Sel = Menu->ItemCount - 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SL_KEY_F1:
|
|
case SL_KEY_F3:
|
|
case ASCI_CR:
|
|
case ASCI_ESC:
|
|
*Selection = Sel;
|
|
#ifdef EFI
|
|
//
|
|
// reset efi watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
return(c);
|
|
|
|
}
|
|
|
|
if (Sel < TopItem) {
|
|
TopItem = Sel;
|
|
SlpDrawMenu(X, Y,
|
|
TopItem,
|
|
Height,
|
|
Menu);
|
|
} else if (Sel > TopItem+Height-3) {
|
|
TopItem = Sel - Height + 3;
|
|
SlpDrawMenu(X, Y,
|
|
TopItem,
|
|
Height,
|
|
Menu);
|
|
}
|
|
//
|
|
// highlight default selection
|
|
//
|
|
SlSetCurrentAttribute(INVATT);
|
|
SlpDrawMenuItem(X,Y,
|
|
TopItem,
|
|
Sel,
|
|
Menu);
|
|
SlSetCurrentAttribute(DEFATT);
|
|
|
|
|
|
} while ( TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SlpDrawMenu(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG TopItem,
|
|
IN ULONG Height,
|
|
IN PSL_MENU Menu
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the menu on the screen
|
|
|
|
Arguments:
|
|
|
|
X - Supplies X coordinate of upper-left corner of menu
|
|
|
|
Y - Supplies Y coordinate of upper-left corner of menu
|
|
|
|
TopItem - Supplies index of item at the top of the menu
|
|
|
|
Height - Supplies the height of the menu
|
|
|
|
Menu - Supplies the menu to be displayed
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PSL_MENUITEM Item;
|
|
ULONG Count;
|
|
TCHAR Output[80];
|
|
ULONG Length;
|
|
ULONG MenuWidth;
|
|
|
|
MenuWidth = Menu->Width+4;
|
|
Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleDown);
|
|
for (i=1;i<MenuWidth-1;i++) {
|
|
Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
|
|
}
|
|
Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleDown);
|
|
SlPositionCursor(X,Y);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
|
|
//
|
|
// Find first item to display
|
|
//
|
|
Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
for (i=0;i<TopItem;i++) {
|
|
Item = CONTAINING_RECORD(Item->ListEntry.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
}
|
|
|
|
//
|
|
// Display items
|
|
//
|
|
Output[0]=
|
|
Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleVertical);
|
|
for (i=Y+1;i<Y+Height-1;i++) {
|
|
#ifdef UNICODE
|
|
for (Count = 0 ; Count < MenuWidth-2;Count++) {
|
|
Output[1+Count] = TEXT(' ');
|
|
}
|
|
#else
|
|
RtlFillMemory(Output+1,(MenuWidth-2)*sizeof(TCHAR),' ');
|
|
#endif
|
|
SlPositionCursor(X, i);
|
|
|
|
if (&Item->ListEntry != &Menu->ItemListHead) {
|
|
Length = (ULONG)_tcslen(Item->Text);
|
|
if (Menu->Width < Length) {
|
|
Length = Menu->Width;
|
|
}
|
|
RtlCopyMemory(Output+2,Item->Text,Length*sizeof(TCHAR));
|
|
Item = CONTAINING_RECORD(Item->ListEntry.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
}
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
|
|
}
|
|
Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleUp);
|
|
for (i=1;i<MenuWidth-1;i++) {
|
|
Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
|
|
}
|
|
Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleUp);
|
|
SlPositionCursor(X,Y+Height-1);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlpDrawMenuItem(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG TopItem,
|
|
IN ULONG Item,
|
|
IN PSL_MENU Menu
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Redraws the given item
|
|
|
|
Arguments:
|
|
|
|
X - Supplies X coordinate of upper-left corner of menu
|
|
|
|
Y - Supplies Y coordinate of upper-left corner of menu
|
|
|
|
TopItem - Supplies index of item at the top of the menu
|
|
|
|
Height - Supplies the height of the menu
|
|
- We had been passing in the Menu Height. But we have no use for
|
|
- it, since we are already assuming that the menu item id exists,
|
|
- so therefore we are writing exactly one line.
|
|
|
|
Item - Supplies the index of the item to be redrawn
|
|
|
|
Menu - Supplies the menu to be displayed
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PSL_MENUITEM MenuItem;
|
|
ULONG Count;
|
|
TCHAR Width[80];
|
|
|
|
//
|
|
// Find item to display
|
|
//
|
|
MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
for (i=0;i<Item;i++) {
|
|
MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
|
|
SL_MENUITEM,
|
|
ListEntry);
|
|
|
|
#if DBG
|
|
if (&MenuItem->ListEntry == &Menu->ItemListHead) {
|
|
SlError(Item);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
for (Count = 0 ; Count < Menu->Width;Count++) {
|
|
Width[Count] = TEXT(' ');
|
|
}
|
|
#else
|
|
RtlFillMemory(Width,(Menu->Width)*sizeof(TCHAR),' ');
|
|
#endif
|
|
|
|
|
|
|
|
RtlCopyMemory(
|
|
Width,
|
|
MenuItem->Text,
|
|
_tcslen(MenuItem->Text)*sizeof(TCHAR) );
|
|
SlPositionCursor(X+2, Y+(Item-TopItem)+1);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,Width,Menu->Width*sizeof(TCHAR),&Count);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SlInitDisplay(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clears the screen and does some initialization of global variables based
|
|
on the ARC display information.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifndef EFI
|
|
PARC_DISPLAY_STATUS DisplayStatus;
|
|
|
|
//
|
|
// Check to see if this version of the ARC firmware is revision 2 or above.
|
|
//
|
|
// If not, we default to 80x25
|
|
//
|
|
if ((SYSTEM_BLOCK->Version > 1) ||
|
|
((SYSTEM_BLOCK->Version == 1) && (SYSTEM_BLOCK->Revision >= 2))) {
|
|
|
|
//
|
|
// Additional checks are required on 1.2 firmware, since some
|
|
// 1.2 firmware does not implement ArcGetDisplayStatus
|
|
//
|
|
if ((SYSTEM_BLOCK->FirmwareVectorLength > (ULONG)GetDisplayStatusRoutine*sizeof(PVOID)) &&
|
|
(SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] != NULL)) {
|
|
DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
|
|
|
|
ScreenWidth = DisplayStatus->CursorMaxXPosition;
|
|
ScreenHeight = DisplayStatus->CursorMaxYPosition;
|
|
}
|
|
}
|
|
|
|
#ifdef ARCI386
|
|
SlPrint(ASCI_CSI_OUT "2J"); // Clears Screen
|
|
|
|
SlSetCurrentAttribute(DEFATT);
|
|
//
|
|
// This is a patch to setup VGA colors in the text port.
|
|
// Otherwise screen colors and attributes are not the same as a PC
|
|
//
|
|
// Write all the attributes to the textport
|
|
{
|
|
int row;
|
|
TCHAR text[MAX_STATUS+1];
|
|
ULONG Count,Length;
|
|
_stprintf(text,TEXT(" "));
|
|
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
// 1 2 3 4 5 6 7 8
|
|
for (row=0; row< 48; row++) // compensate for the long textport 48 versus 24 (VGA)
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,text,strlen(&text[0]),&Count);
|
|
}
|
|
// Position cursor at Top Left of screen
|
|
SlPositionCursor(0,0);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef EFI
|
|
//
|
|
// On EFI, we won't be redirecting because setupldr.efi is an
|
|
// EFI application. If that's the case, then we can't use
|
|
// BlIsTerminalConnected(). Instead, we're going to look
|
|
// at the values in the LoaderRedirectionInformation structure
|
|
// to see if we're really redirecting.
|
|
//
|
|
if( LoaderRedirectionInformation.PortAddress != 0 ) {
|
|
#else
|
|
if (BlIsTerminalConnected()) {
|
|
#endif
|
|
ScreenHeight = HEADLESS_SCREEN_HEIGHT;
|
|
}
|
|
|
|
|
|
SlSetCurrentAttribute(DEFATT);
|
|
SlClearDisplay();
|
|
}
|
|
|
|
|
|
VOID
|
|
SlPrint(
|
|
IN PTCHAR FormatString,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
TCHAR text[MAX_STATUS+1];
|
|
ULONG Count,Length;
|
|
ULONG MaxWidth = ScreenWidth - 2;
|
|
|
|
if (MaxWidth > MAX_STATUS) {
|
|
MaxWidth = MAX_STATUS;
|
|
}
|
|
|
|
va_start(arglist,FormatString);
|
|
Length = _vsntprintf(text,MaxWidth*sizeof(TCHAR),FormatString,arglist);
|
|
text[MaxWidth] = TEXT('\0');
|
|
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count);
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlClearDisplay(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clears the entire display, including header, client area, and status line.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if 1
|
|
BlClearScreen();
|
|
#else
|
|
|
|
SlPositionCursor(0,0);
|
|
|
|
#ifdef EFI
|
|
BlEfiClearToEndOfDisplay();
|
|
#else
|
|
ARC_DISPLAY_CLEAR_TO_EOD();
|
|
#endif
|
|
|
|
if (!ShowProgressBar) {
|
|
SlWriteStatusText(TEXT(""));
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
ARC_STATUS
|
|
SlClearClientArea(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clears the client area of the screen. Does not disturb the header or
|
|
status areas.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
always ESUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT i;
|
|
|
|
for(i=HEADER_HEIGHT; i<ScreenHeight-1; i++) {
|
|
SlPositionCursor(0,i);
|
|
SlClearToEol();
|
|
}
|
|
|
|
//
|
|
// home cursor
|
|
//
|
|
|
|
SlPositionCursor(0,0);
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SlClearToEol(
|
|
VOID
|
|
)
|
|
{
|
|
#ifdef EFI
|
|
|
|
BlEfiClearToEndOfLine();
|
|
#else
|
|
ARC_DISPLAY_CLEAR_TO_EOL();
|
|
#endif
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlGetCursorPosition(
|
|
OUT unsigned *x,
|
|
OUT unsigned *y
|
|
)
|
|
{
|
|
*x = ScreenX;
|
|
*y = ScreenY;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SlPositionCursor(
|
|
IN unsigned x,
|
|
IN unsigned y
|
|
)
|
|
{
|
|
//
|
|
// clip to screen
|
|
//
|
|
|
|
if(x>=ScreenWidth) {
|
|
x = ScreenWidth-1;
|
|
}
|
|
|
|
if(y>=ScreenHeight) {
|
|
y = ScreenHeight-1;
|
|
}
|
|
|
|
ScreenX = x;
|
|
ScreenY = y;
|
|
|
|
#ifdef EFI
|
|
BlEfiPositionCursor(x, y );
|
|
#else
|
|
ARC_DISPLAY_POSITION_CURSOR(x, y);
|
|
#endif
|
|
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SlWriteString(
|
|
IN PTCHAR s
|
|
)
|
|
{
|
|
PTCHAR p = s,q;
|
|
BOOLEAN done = FALSE;
|
|
ULONG len,count;
|
|
|
|
do {
|
|
q = p;
|
|
while((*q != TEXT('\0')) && (*q != TEXT('\n'))) {
|
|
q++;
|
|
}
|
|
if(*q == TEXT('\0')) {
|
|
done = TRUE;
|
|
} else {
|
|
*q = TEXT('\0');
|
|
}
|
|
len = (ULONG)(q - p);
|
|
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,p,len*sizeof(TCHAR),&count);
|
|
|
|
ScreenX += len;
|
|
|
|
if(!done) {
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,TEXT("\r\n"),2*sizeof(TCHAR),&count);
|
|
ScreenX = 0;
|
|
ScreenY++;
|
|
if(ScreenY == ScreenHeight) {
|
|
ScreenY = ScreenHeight-1;
|
|
}
|
|
*q = TEXT('\n');
|
|
}
|
|
p = q + 1;
|
|
} while(!done);
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlSetCurrentAttribute(
|
|
IN UCHAR Attribute
|
|
)
|
|
{
|
|
CurAttribute = Attribute;
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( CurAttribute );
|
|
#else
|
|
|
|
SlPrint(ASCI_CSI_OUT);
|
|
|
|
if (BlIsTerminalConnected() &&
|
|
((Attribute == DEFSTATTR) ||
|
|
(Attribute == INVATT))) {
|
|
SlPrint(TEXT("7"));
|
|
} else {
|
|
SlPrint(TEXT("0"));
|
|
}
|
|
|
|
SlPrint(TEXT(";%u;%um"), (Attribute & 0x7) + 30, ((Attribute >> 4) & 7) + 40);
|
|
|
|
if(Attribute & ATT_FG_INTENSE) {
|
|
SlPrint(ASCI_CSI_OUT TEXT("1m"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
SlWriteHeaderText(
|
|
IN ULONG MsgId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the header on the screen with a given string
|
|
|
|
Arguments:
|
|
|
|
MsgId - Supplies the message ID of the new string to be displayed. This should
|
|
be just one line long. If it is 0, the header is cleared.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
|
|
for(i=HEADER_HEIGHT-1; i>=0; i--) {
|
|
SlPositionCursor(0,i);
|
|
SlClearToEol();
|
|
}
|
|
|
|
if (MsgId != 0) {
|
|
SlWriteString(BlFindMessage(MsgId));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stores the current status text. The size is the screen width, plus the
|
|
// terminating nul char.
|
|
//
|
|
TCHAR StatusText[MAX_STATUS];
|
|
|
|
UCHAR StatusAttribute = DEFSTATTR;
|
|
|
|
VOID
|
|
SlSetStatusAttribute(
|
|
IN UCHAR Attribute
|
|
)
|
|
{
|
|
StatusAttribute = Attribute;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlGetStatusBarStatus(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if status bar is enabled or not
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE or FALSE
|
|
--*/
|
|
{
|
|
return StatusBarEnabled;
|
|
}
|
|
|
|
VOID
|
|
SlEnableStatusBar(
|
|
IN BOOLEAN Enable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enables or disables the status bar
|
|
|
|
Arguments:
|
|
|
|
Enabled - Enable/Disable = TRUE/FALSE
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
StatusBarEnabled = Enable;
|
|
}
|
|
|
|
VOID
|
|
SlWriteStatusText(
|
|
IN PTCHAR Text
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the status area on the screen with a given string
|
|
|
|
Arguments:
|
|
|
|
Text - Supplies the new text for the status area.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UCHAR AttributeSave = CurAttribute;
|
|
PTCHAR p;
|
|
ULONG Count;
|
|
#ifdef EFI
|
|
ULONG MaxWidth = ScreenWidth - 3;
|
|
#else
|
|
ULONG MaxWidth = ScreenWidth - 2;
|
|
#endif
|
|
|
|
//
|
|
// Nop, if status bar is disabled
|
|
//
|
|
if (!StatusBarEnabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if we're writing to a terminal, we don't want to write into the lower
|
|
// right corner as this would make us scroll.
|
|
//
|
|
if (BlTerminalConnected) {
|
|
MaxWidth -= 1;
|
|
}
|
|
|
|
if (MaxWidth > MAX_STATUS) {
|
|
MaxWidth = MAX_STATUS;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
for (Count = 0 ; Count < sizeof(StatusText)/sizeof(TCHAR);Count++) {
|
|
StatusText[Count] = TEXT(' ');
|
|
}
|
|
#else
|
|
RtlFillMemory(StatusText,sizeof(StatusText),' ');
|
|
#endif
|
|
|
|
//
|
|
// Strip cr/lf as we copy the status text into the status text buffer.
|
|
//
|
|
p = StatusText;
|
|
Count = 0;
|
|
while((Count < MaxWidth) && *Text) {
|
|
if((*Text != TEXT('\r')) && (*Text != TEXT('\n'))) {
|
|
*p++ = *Text;
|
|
Count++;
|
|
}
|
|
Text++;
|
|
}
|
|
|
|
SlSetCurrentAttribute(StatusAttribute);
|
|
SlPositionCursor(0,ScreenHeight-1);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,TEXT(" "),2*sizeof(TCHAR),&Count);
|
|
SlPositionCursor(2,ScreenHeight-1);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,StatusText,MaxWidth*sizeof(TCHAR),&Count);
|
|
SlSetCurrentAttribute(AttributeSave);
|
|
SlPositionCursor(0,5);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlGetStatusText(
|
|
OUT PTCHAR Text
|
|
)
|
|
{
|
|
_tcscpy(Text,StatusText);
|
|
}
|
|
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
SlWriteDbgText(
|
|
IN PTCHAR text
|
|
)
|
|
{
|
|
UCHAR SavedAttribute = CurAttribute;
|
|
|
|
SlPositionCursor(0,0);
|
|
CurAttribute = ATT_FG_YELLOW | ATT_BG_RED | ATT_FG_INTENSE;
|
|
|
|
SlClearToEol();
|
|
SlWriteString(text);
|
|
|
|
CurAttribute = SavedAttribute;
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
SlFlushConsoleBuffer(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine flushes the console buffer, so that we don't have any
|
|
pre-existing keypresses in the buffer when we prompt the user to
|
|
'press any key to continue.'
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR c;
|
|
ULONG count;
|
|
|
|
while(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
SlGetChar(
|
|
VOID
|
|
)
|
|
{
|
|
UCHAR c;
|
|
ULONG count;
|
|
|
|
ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
|
|
|
|
if(c == ASCI_CSI_IN) {
|
|
if (ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
|
|
//
|
|
// Just a single escape - return it
|
|
//
|
|
return (ASCI_ESC);
|
|
}
|
|
|
|
ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
|
|
|
|
switch(c) {
|
|
|
|
//
|
|
// see ntos\fw\mips\fwsignal.c!TranslateScanCode() for these codes.
|
|
// Additional codes that might be useful someday:
|
|
// left=C, right=D, insert=@, delete=P
|
|
//
|
|
|
|
case 'A': // up arrow
|
|
return(SL_KEY_UP);
|
|
|
|
case 'B': // down arrow
|
|
return(SL_KEY_DOWN);
|
|
|
|
case 'H': // home
|
|
return(SL_KEY_HOME);
|
|
|
|
case 'K': // end
|
|
return(SL_KEY_END);
|
|
|
|
case '?': // page up
|
|
return(SL_KEY_PAGEUP);
|
|
|
|
case '/': // page down
|
|
return(SL_KEY_PAGEDOWN);
|
|
|
|
case 'O': // function keys
|
|
|
|
ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
|
|
|
|
//
|
|
// F1=P, F2=Q, F3=w, F4 =x, F5 =t, F6 =u
|
|
// F7=q, F8=r, F9=p, F10=m, F11=A, F12=B
|
|
//
|
|
// Note: as of 12/15/92, f11 and f12 were commented out in the
|
|
// firmware sources so are probably never returned.
|
|
//
|
|
|
|
switch(c) {
|
|
|
|
case 'P':
|
|
return(SL_KEY_F1);
|
|
|
|
case 'Q':
|
|
return(SL_KEY_F2);
|
|
|
|
case 'w':
|
|
return(SL_KEY_F3);
|
|
|
|
case 'x':
|
|
return(SL_KEY_F4);
|
|
|
|
|
|
case 't':
|
|
return(SL_KEY_F5);
|
|
|
|
|
|
case 'u':
|
|
return(SL_KEY_F6);
|
|
|
|
case 'q':
|
|
return(SL_KEY_F7);
|
|
|
|
case 'r':
|
|
return SL_KEY_F8;
|
|
|
|
case 'm':
|
|
case 'M':
|
|
return SL_KEY_F10;
|
|
|
|
case 'A':
|
|
return(SL_KEY_F11);
|
|
|
|
case 'B':
|
|
return(SL_KEY_F12);
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
|
|
} else {
|
|
if(c == ASCI_LF) {
|
|
c = ASCI_CR;
|
|
}
|
|
return((ULONG)c);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlPromptForDisk(
|
|
IN PTCHAR DiskName,
|
|
IN BOOLEAN IsCancellable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine prompts a user to insert a given diskette #, or to abort the
|
|
Setup process.
|
|
|
|
The status line will be erased.
|
|
|
|
Arguments:
|
|
|
|
DiskName - Supplies the name of the disk to be inserted.
|
|
|
|
IsCancellable - Supplies flag indicating whether prompt may be cancelled.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The user has pressed OK
|
|
|
|
FALSE - The user has pressed CANCEL
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG msg;
|
|
ULONG y;
|
|
ULONG Key;
|
|
PTCHAR Text;
|
|
PTCHAR PleaseWait;
|
|
ULONG i;
|
|
TCHAR DiskNameDisplayed[81];
|
|
BOOLEAN Repaint=TRUE;
|
|
|
|
SlWriteStatusText(TEXT(""));
|
|
|
|
if(IsCancellable) {
|
|
msg = SL_NEXT_DISK_PROMPT_CANCELLABLE;
|
|
} else {
|
|
msg = SL_NEXT_DISK_PROMPT;
|
|
}
|
|
Text = BlFindMessage(msg);
|
|
if(Text == NULL) {
|
|
SlError(msg);
|
|
return(FALSE);
|
|
}
|
|
|
|
PleaseWait = BlFindMessage(SL_PLEASE_WAIT);
|
|
if(PleaseWait == NULL) {
|
|
SlError(SL_PLEASE_WAIT);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Get first line of DiskName and save it in DiskNameDisplayed (limit to 80 chars)
|
|
//
|
|
for(i = 0;
|
|
((i < 80) && DiskName[i] && (DiskName[i] != TEXT('\r')) && (DiskName[i] != TEXT('\n')));
|
|
i++)
|
|
{
|
|
DiskNameDisplayed[i] = DiskName[i];
|
|
}
|
|
DiskNameDisplayed[i] = TEXT('\0');
|
|
|
|
do {
|
|
if (Repaint) {
|
|
SlClearClientArea();
|
|
y = SlDisplayMessageBox(SL_MSG_INSERT_DISK);
|
|
SlPositionCursor((ScreenWidth-i)/2,y+2);
|
|
SlWriteString(DiskNameDisplayed);
|
|
SlWriteStatusText(Text);
|
|
}
|
|
Repaint = FALSE;
|
|
SlFlushConsoleBuffer();
|
|
#ifdef EFI
|
|
//
|
|
// diable EFI watchdog when prompting for user input
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
Key = SlGetChar();
|
|
#ifdef EFI
|
|
//
|
|
// reset EFI watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
if (Key == ASCI_CR) {
|
|
SlClearClientArea();
|
|
SlWriteStatusText(PleaseWait);
|
|
return(TRUE);
|
|
} else if (Key == SL_KEY_F3) {
|
|
SlConfirmExit();
|
|
Repaint=TRUE;
|
|
} else if((Key == ASCI_ESC) && IsCancellable) {
|
|
SlWriteStatusText(TEXT(""));
|
|
SlClearClientArea();
|
|
return FALSE;
|
|
}
|
|
} while ( TRUE );
|
|
}
|
|
|
|
|
|
VOID
|
|
SlConfirmExit(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to be called when user presses F3. Confirms that he really wants
|
|
to exit by popping up a dialog. DOES NOT RETURN if user chooses to exit.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG c;
|
|
|
|
//
|
|
// if we use too much stack space the heap and stack can overlap and we can run into corruption problems
|
|
// without any "stack overflow" exceptions; making large strings static helps prevent this
|
|
//
|
|
static TCHAR OldStatus[MAX_STATUS];
|
|
PTCHAR Text;
|
|
|
|
SlGetStatusText(OldStatus);
|
|
|
|
SlClearClientArea();
|
|
|
|
SlSetCurrentAttribute(DEFDLGATT);
|
|
|
|
SlDisplayMessageBox(SL_MSG_EXIT_DIALOG);
|
|
|
|
SlSetCurrentAttribute(DEFATT);
|
|
|
|
SlFlushConsoleBuffer();
|
|
|
|
#ifdef EFI
|
|
//
|
|
// Disable EFI watchdog
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
while(1) {
|
|
c = SlGetChar();
|
|
if(c == ASCI_CR) {
|
|
SlWriteStatusText(OldStatus);
|
|
#ifdef EFI
|
|
//
|
|
// reset EFI watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
return;
|
|
}
|
|
if(c == SL_KEY_F3) {
|
|
Text = BlFindMessage(SL_REBOOT_PROMPT);
|
|
SlClearClientArea();
|
|
#ifdef i386
|
|
SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED);
|
|
#else
|
|
SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED_ARC);
|
|
#endif
|
|
SlWriteStatusText(Text);
|
|
|
|
SlFlushConsoleBuffer();
|
|
while(SlGetChar() != ASCI_CR);
|
|
ArcRestart();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SlFriendlyError(
|
|
IN ULONG uStatus,
|
|
IN PCHAR pchBadFile,
|
|
IN ULONG uLine,
|
|
IN PCHAR pchCodeFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when an error occurs. It puts up a
|
|
message box, displays an informative message, and allows
|
|
the user to continue. It is intended to give friendlier
|
|
messages than the SlError macro, in the cases where SlError
|
|
gets passed ARC error codes.
|
|
|
|
The status text line will be erased.
|
|
|
|
Arguments:
|
|
|
|
uStatus - ARC error code
|
|
|
|
pchBadFile - Name of file causing error (Must be given for handled
|
|
ARC codes. Optional for unhandled codes.)
|
|
|
|
uLine - Line # in source code file where error occurred (only
|
|
used for unhandled codes.)
|
|
|
|
pchCodeFile - Name of souce code file where error occurred (only
|
|
used for unhandled codes.)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG uMsg;
|
|
PTSTR pBadFile;
|
|
PTSTR pCodeFile;
|
|
#ifdef UNICODE
|
|
WCHAR BadFileW[64];
|
|
WCHAR CodeFileW[200];
|
|
ANSI_STRING aString;
|
|
UNICODE_STRING uString;
|
|
|
|
RtlInitString( &aString, pchBadFile );
|
|
uString.Buffer = BadFileW;
|
|
uString.MaximumLength = sizeof(BadFileW);
|
|
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
|
|
|
RtlInitString( &aString, pchCodeFile );
|
|
uString.Buffer = CodeFileW;
|
|
uString.MaximumLength = sizeof(CodeFileW);
|
|
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
|
|
|
if (pchBadFile) {
|
|
pBadFile = BadFileW;
|
|
} else {
|
|
pBadFile = NULL;
|
|
}
|
|
|
|
pCodeFile = CodeFileW;
|
|
|
|
#else
|
|
pBadFile = pchBadFile;
|
|
pCodeFile = pchCodeFile;
|
|
#endif
|
|
|
|
SlClearClientArea();
|
|
switch(uStatus) {
|
|
case EBADF:
|
|
case EINVAL: // image corrupt
|
|
uMsg = SL_WARNING_IMG_CORRUPT;
|
|
break;
|
|
|
|
case EIO: // i/o error
|
|
uMsg = SL_WARNING_IOERR;
|
|
break;
|
|
|
|
case ENOENT: // file not found
|
|
uMsg = SL_WARNING_NOFILE;
|
|
break;
|
|
|
|
case ENOMEM: // insufficient memory
|
|
uMsg = SL_WARNING_NOMEM;
|
|
break;
|
|
|
|
case EACCES: // unrecognized file system
|
|
uMsg = SL_WARNING_BAD_FILESYS;
|
|
break;
|
|
|
|
default: // then get SlError() behavior (with optional bad file name)
|
|
if(pBadFile) { // include error-causing file's name
|
|
SlMessageBox(
|
|
SL_WARNING_ERROR_WFILE,
|
|
pBadFile,
|
|
uStatus,
|
|
uLine,
|
|
pCodeFile
|
|
);
|
|
} else {
|
|
SlMessageBox(
|
|
SL_WARNING_ERROR,
|
|
uStatus,
|
|
uLine,
|
|
pCodeFile
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
SlMessageBox(
|
|
uMsg,
|
|
pBadFile
|
|
);
|
|
}
|
|
|
|
VOID
|
|
SlMessageBox(
|
|
IN ULONG MessageId,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when an error occurs. It puts up a
|
|
message box, displays an informative message, and allows
|
|
the user to continue.
|
|
|
|
The status text line will be erased.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Supplies ID of message box to be presented.
|
|
|
|
any sprintf-compatible arguments to be inserted in the
|
|
message box.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
va_list args;
|
|
|
|
SlClearClientArea();
|
|
va_start(args, MessageId);
|
|
SlGenericMessageBox(MessageId, &args, NULL, NULL, NULL, NULL, TRUE);
|
|
va_end(args);
|
|
|
|
SlFlushConsoleBuffer();
|
|
SlGetChar();
|
|
}
|
|
|
|
|
|
ULONG
|
|
SlDisplayMessageBox(
|
|
IN ULONG MessageId,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Just puts a message box up on the screen and returns.
|
|
|
|
The status text line will be erased.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Supplies ID of message box to be presented.
|
|
|
|
any sprintf-compatible arguments to be inserted in the
|
|
message box.
|
|
|
|
Return Value:
|
|
|
|
Y position of top line of message box
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG y;
|
|
va_list args;
|
|
|
|
va_start(args, MessageId);
|
|
SlGenericMessageBox(MessageId, &args, NULL, NULL, &y, NULL, TRUE);
|
|
va_end(args);
|
|
|
|
return(y);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlFatalError(
|
|
IN ULONG MessageId,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when a fatal error occurs. It clears the client
|
|
area, puts up a message box, displays the fatal error message, and
|
|
allows the user to press a key to reboot.
|
|
|
|
The status text line will be erased.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Supplies ID of message box to be presented.
|
|
|
|
any sprintf-compatible arguments to be inserted in the
|
|
message box.
|
|
|
|
Return Value:
|
|
|
|
Does not return.
|
|
|
|
--*/
|
|
|
|
{
|
|
va_list args;
|
|
ULONG x,y;
|
|
PTCHAR Text;
|
|
|
|
SlClearClientArea();
|
|
|
|
Text = BlFindMessage(MessageId);
|
|
if(Text) {
|
|
|
|
va_start(args, MessageId);
|
|
|
|
_vsntprintf(MessageBuffer, sizeof(MessageBuffer), Text, args);
|
|
MessageBuffer[sizeof(MessageBuffer)-1] = '\0';
|
|
|
|
//
|
|
// Add a blank line, then concatenate the 'Can't continue' text.
|
|
//
|
|
_tcscat(MessageBuffer, TEXT("\r\n"));
|
|
|
|
Text = BlFindMessage(SL_CANT_CONTINUE);
|
|
if(Text) {
|
|
_tcscat(MessageBuffer, Text);
|
|
}
|
|
|
|
Text = BlAllocateHeap(((ULONG)_tcslen(MessageBuffer)+1) * sizeof(TCHAR));
|
|
_tcscpy(Text, MessageBuffer);
|
|
|
|
//
|
|
// Note that MessageId and args won't be used, since we're
|
|
// passing in our Text pointer.
|
|
//
|
|
SlGenericMessageBox(MessageId, &args, Text, &x, NULL, &y, TRUE);
|
|
|
|
va_end(args);
|
|
|
|
} else {
|
|
SlError(MessageId);
|
|
}
|
|
|
|
SlFlushConsoleBuffer();
|
|
|
|
SlGetChar();
|
|
|
|
ArcRestart();
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SlGenericMessageBox(
|
|
IN ULONG MessageId, OPTIONAL
|
|
IN va_list *args, OPTIONAL
|
|
IN PTCHAR Message, OPTIONAL
|
|
IN OUT PULONG xLeft, OPTIONAL
|
|
IN OUT PULONG yTop, OPTIONAL
|
|
OUT PULONG yBottom, OPTIONAL
|
|
IN BOOLEAN bCenterMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats and displays a message box. The longest line in the string
|
|
of characters will be centered on the screen if bCenterMsg is TRUE.
|
|
|
|
The status text line will be erased.
|
|
|
|
Arguments:
|
|
|
|
NOTE: Either the MessageId/args pair or the Message string must be
|
|
specified. Message string will be used if non-NULL.
|
|
|
|
MessageId - Supplies the MessageId that will be looked up to provide
|
|
a NULL-terminated string of characters.
|
|
Each \r\n delimited string will be displayed on its own line.
|
|
|
|
args - Supplies the argument list that will be passed to vsprintf.
|
|
|
|
Message - Supplies the actual text of the message to be displayed
|
|
|
|
xLeft - If bCenterMsg is FALSE, then xLeft is used for the starting x
|
|
coordinate of the message (if specified, otherwise, x = 1).
|
|
Also, if specified, it receives the x coordinate of the left edge
|
|
of all lines that were displayed.
|
|
|
|
yTop - If bCenterMsg is FALSE, then yTop is used for the starting y
|
|
coordinate of the message (if specified, otherwise, y = 3).
|
|
Also, if specified, receives the y coordinate of the top line where
|
|
the message box was displayed.
|
|
|
|
yBottom - if specified, receives the y coordinate of the bottom line of
|
|
the message box.
|
|
|
|
bCenterMsg - if TRUE, center message on the screen.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCHAR p;
|
|
ULONG NumLines;
|
|
ULONG MaxLength;
|
|
ULONG x;
|
|
ULONG y;
|
|
ULONG i;
|
|
PTCHAR Line[20];
|
|
ULONG LineLength[20];
|
|
ULONG Count;
|
|
|
|
//
|
|
// set some default position values
|
|
//
|
|
x = 3;
|
|
y = ScreenHeight/2;
|
|
NumLines = 0;
|
|
|
|
if(!Message) { // then look up the message
|
|
p=BlFindMessage(MessageId);
|
|
if (p==NULL) {
|
|
SlError(MessageId);
|
|
} else {
|
|
_vsntprintf(MessageBuffer,sizeof(MessageBuffer),p,*args);
|
|
Message = MessageBuffer;
|
|
}
|
|
} else {
|
|
//
|
|
// Just make p non-NULL, so we'll know it's OK to continue.
|
|
//
|
|
p = Message;
|
|
}
|
|
|
|
if(p) {
|
|
|
|
SlWriteStatusText(TEXT("")); // Clear status bar
|
|
|
|
SlpSizeMessage(Message,
|
|
&NumLines,
|
|
&MaxLength,
|
|
LineLength,
|
|
Line);
|
|
|
|
if (MaxLength > ScreenWidth) {
|
|
MaxLength = ScreenWidth;
|
|
}
|
|
|
|
if(bCenterMsg) {
|
|
x = (ScreenWidth-MaxLength)/2;
|
|
y = (ScreenHeight-NumLines)/2;
|
|
} else {
|
|
if(xLeft) {
|
|
x = *xLeft;
|
|
} else {
|
|
x = 1;
|
|
}
|
|
|
|
if(yTop) {
|
|
y = *yTop;
|
|
} else {
|
|
y = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0; i<NumLines; i++) {
|
|
SlPositionCursor(x, y+i);
|
|
ArcWrite(ARC_CONSOLE_OUTPUT,Line[i],LineLength[i]*sizeof(TCHAR),&Count);
|
|
}
|
|
|
|
if(xLeft) {
|
|
*xLeft = x;
|
|
}
|
|
|
|
if(yTop) {
|
|
*yTop = y;
|
|
}
|
|
|
|
if(yBottom) {
|
|
*yBottom = NumLines ? y+NumLines-1 : 0;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SlpSizeMessage(
|
|
IN PTCHAR Message,
|
|
OUT PULONG Lines,
|
|
OUT PULONG MaxLength,
|
|
OUT ULONG LineLength[],
|
|
OUT PTCHAR LineText[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine walks down a message and determines the number of
|
|
lines and the maximum line length.
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies a pointer to a null-terminated message
|
|
|
|
Lines - Returns the number of lines
|
|
|
|
MaxLength - Returns the length of the longest line.
|
|
|
|
LineLength - Supplies a pointer to an array of ULONGs
|
|
Returns a filled in array containing the
|
|
length of each line.
|
|
|
|
LineText - Supplies a pointer to an array of PCHARs
|
|
Returns a filled in array containing a
|
|
pointer to the start of each line.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCHAR p;
|
|
ULONG NumLines;
|
|
ULONG Length;
|
|
|
|
p = Message;
|
|
NumLines = 0;
|
|
*MaxLength = 0;
|
|
Length = 0;
|
|
|
|
//
|
|
// walk through the string, determining the number of lines
|
|
// and the length of the longest line.
|
|
//
|
|
LineText[0]=p;
|
|
while (*p != TEXT('\0')) {
|
|
if ((*p == TEXT('\r')) && (*(p+1) == TEXT('\n'))) {
|
|
//
|
|
// End of a line.
|
|
//
|
|
|
|
if (Length > *MaxLength) {
|
|
*MaxLength = Length;
|
|
}
|
|
LineLength[NumLines] = Length;
|
|
++NumLines;
|
|
Length = 0;
|
|
p += 2;
|
|
LineText[NumLines] = p;
|
|
|
|
} else {
|
|
++Length;
|
|
++p;
|
|
|
|
if (*p == TEXT('\0')) {
|
|
|
|
//
|
|
// End of the message.
|
|
//
|
|
|
|
if (Length > *MaxLength) {
|
|
*MaxLength = Length;
|
|
}
|
|
LineLength[NumLines] = Length;
|
|
++NumLines;
|
|
}
|
|
}
|
|
}
|
|
|
|
*Lines = NumLines;
|
|
|
|
}
|
|
|
|
VOID
|
|
SlNoMemError(
|
|
IN ULONG Line,
|
|
IN PCHAR File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
|
|
|
|
Arguments:
|
|
|
|
Line - Line number within the file the error occurred on.
|
|
|
|
File - File name where the error occurred.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
SlFatalError(SL_NO_MEMORY, Line, SlCopyStringAT(File));
|
|
}
|
|
|
|
VOID
|
|
SlBadInfLineError(
|
|
IN ULONG Line,
|
|
IN PCHAR INFFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
|
|
|
|
Arguments:
|
|
|
|
Line - Line number within the inf file the error occurred on.
|
|
|
|
INFFile - Supplies a pointer to the INF filename.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
SlFatalError(SL_BAD_INF_LINE, Line, SlCopyStringAT(INFFile));
|
|
}
|
|
|
|
VOID
|
|
SlErrorBox(
|
|
IN ULONG MessageId,
|
|
IN ULONG Line,
|
|
IN PCHAR File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Id of the message to display.
|
|
|
|
Line - Line number within the file the error occurred on.
|
|
|
|
File - File name where the error occurred.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PTSTR pFile;
|
|
#ifdef UNICODE
|
|
WCHAR FileW[200];
|
|
ANSI_STRING aString;
|
|
UNICODE_STRING uString;
|
|
|
|
RtlInitString( &aString, File );
|
|
uString.Buffer = FileW;
|
|
uString.MaximumLength = sizeof(FileW);
|
|
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
|
|
|
pFile = FileW;
|
|
|
|
#else
|
|
pFile = File;
|
|
#endif
|
|
|
|
|
|
SlMessageBox(SL_WARNING_ERROR, MessageId, Line, pFile);
|
|
}
|