예제 #1
0
VOID
SlWriteStatusText(
    IN PCHAR 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;
    CHAR *p;
    ULONG Count;
    ULONG MaxWidth = ScreenWidth - 2;

    if (MaxWidth > MAX_STATUS) {
        MaxWidth = MAX_STATUS;
    }

    RtlFillMemory(StatusText,sizeof(StatusText),' ');

    //
    // Strip cr/lf as we copy the status text into the status text buffer.
    //
    p = StatusText;
    Count = 0;
    while((Count < MaxWidth) && *Text) {
        if((*Text != '\r') && (*Text != '\n')) {
            *p++ = *Text;
            Count++;
        }
        Text++;
    }

    SlSetCurrentAttribute(StatusAttribute);
    SlPositionCursor(0,ScreenHeight-1);
    ArcWrite(ARC_CONSOLE_OUTPUT,"  ",2,&Count);
    SlPositionCursor(2,ScreenHeight-1);
    ArcWrite(ARC_CONSOLE_OUTPUT,StatusText,MaxWidth*sizeof(CHAR),&Count);
    SlSetCurrentAttribute(AttributeSave);
    SlPositionCursor(0,5);
}
예제 #2
0
void prom_putchar(char c)
{
	ULONG cnt;
	CHAR it = c;

	ArcWrite(1, &it, 1, &cnt);
}
예제 #3
0
//
// output long integer
//
VOID puti(__in LONG i)
{
	UCHAR Value;
	ULONG Count;
	if(i < 0)
	{
		i												= -i;
		Value											= '-';
		ArcWrite(BlConsoleOutDeviceId,&Value,sizeof(Value),&Count);
	}

	if(i / 10)
		puti(i / 10);

	Value												= static_cast<UCHAR>(i % 10) + '0';
	ArcWrite(BlConsoleOutDeviceId,&Value,sizeof(Value),&Count);
}
예제 #4
0
void prom_putchar(char c)
{
	ULONG cnt;
	CHAR it = c;

	bc_disable();
	ArcWrite(1, &it, 1, &cnt);
	bc_enable();
}
예제 #5
0
//
// output an unsigned long
//
VOID putu(__in ULONG u)
{
	if(u / 10)
		putu(u / 10);

	UCHAR Value											= static_cast<UCHAR>(u % 10) + '0';
	ULONG Count;
	ArcWrite(BlConsoleOutDeviceId,&Value,sizeof(Value),&Count);
}
예제 #6
0
//
// output unicode string
//
VOID putwS(__in PUNICODE_STRING String)
{
	for(USHORT i = 0; i < String->Length / sizeof(WCHAR); i ++)
	{
		UCHAR Value										= static_cast<UCHAR>(String->Buffer[i]);
		ULONG Count;
		ArcWrite(BlConsoleOutDeviceId,&Value,sizeof(Value),&Count);
	}
}
예제 #7
0
//
// output hex long
//
VOID putx(__in ULONG x)
{
	if(x >> 4)
		putx(x >> 4);

	UCHAR j												= static_cast<UCHAR>(x & 0xf);
	if(j > 9)
		j												+= ('A' - 10);
	else
		j												+= '0';

	ArcWrite(BlConsoleOutDeviceId,&j,sizeof(j),&x);
}
예제 #8
0
ARC_STATUS
SlWriteString(
    IN PUCHAR s
    )
{
    PUCHAR p = s,q;
    BOOLEAN done = FALSE;
    ULONG len,count;

    do {
        q = p;
        while((*q != '\0') && (*q != '\n')) {
            q++;
        }
        if(*q == '\0') {
            done = TRUE;
        } else {
            *q = '\0';
        }
        len = q - p;

        ArcWrite(ARC_CONSOLE_OUTPUT,p,len,&count);

        ScreenX += len;

        if(!done) {
            ArcWrite(ARC_CONSOLE_OUTPUT,"\r\n",2,&count);
            ScreenX = 0;
            ScreenY++;
            if(ScreenY == ScreenHeight) {
                ScreenY = ScreenHeight-1;
            }
            *q = '\n';
        }
        p = q + 1;
    } while(!done);

    return(ESUCCESS);
}
예제 #9
0
VOID
SlPrint(
    IN PCHAR FormatString,
    ...
    )
{
    va_list arglist;
    CHAR    text[MAX_STATUS+1];
    ULONG   Count,Length;
    ULONG   MaxWidth = ScreenWidth - 2;

    if (MaxWidth > MAX_STATUS) {
        MaxWidth = MAX_STATUS;
    }

    va_start(arglist,FormatString);
    Length = _vsnprintf(text,MaxWidth*sizeof(CHAR),FormatString,arglist);
    text[MaxWidth] = 0;

    ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count);
    va_end(arglist);
}
예제 #10
0
파일: low.c 프로젝트: BuloZB/WinNT4
ARC_STATUS
LowWriteSectors(
    IN  ULONG   VolumeId,
    IN  ULONG   SectorSize,
    IN  ULONG   StartingSector,
    IN  ULONG   NumberOfSectors,
    IN  PVOID   Buffer
    )
/*++

Routine Description:

    This routine write 'NumberOfSectors' sectors starting at sector
    'StartingSector' on the volume with ID 'VolumeId'.

Arguments:

    VolumeId        - Supplies the ID for the volume.
    SectorSize      - Supplies the number of bytes per sector.
    StartingSector  - Supplies the starting sector for the write.
    NumberOfSectors - Supplies the number of sectors to write.
    Buffer          - Supplies the sectors to write.

Return Value:

    ArcSeek, ArcWrite, EIO, ESUCCESS

--*/
{
    ARC_STATUS    r;
    ULONG         c;
    LARGE_INTEGER l;
    ULONG         i;
    ULONG         transfer;
    PCHAR         buf;
    ULONG         total;

    l.QuadPart = UInt32x32To64(StartingSector,SectorSize);

    buf = (PCHAR) Buffer;

    r = ArcSeek(VolumeId, &l, SeekAbsolute);

    if (r != ESUCCESS) {
        return r;
    }

    total = SectorSize*NumberOfSectors;

    for (i = 0; i < total; i += MAX_TRANSFER) {

        transfer = min(MAX_TRANSFER, total - i);

        r = ArcWrite(VolumeId, &buf[i], transfer, &c);

        if (r != ESUCCESS) {
            return r;
        }

        if (c != transfer) {
            return EIO;
        }
    }

    return ESUCCESS;
}
예제 #11
0
GETSTRING_ACTION
JzGetString(
    OUT PCHAR String,
    IN ULONG StringLength,
    IN PCHAR InitialString OPTIONAL,
    IN ULONG CurrentRow,
    IN ULONG CurrentColumn,
    IN BOOLEAN ShowTheTime
    )

/*++

Routine Description:

    This routine reads a string from standardin until a carriage return is
    found, StringLength is reached, or ESC is pushed.

    Semicolons are discarded.  Reason: semicolons are key characters in
    the parsing of multi-segment environment variables.  They aren not
    needed for any valid input to the firmware, so the easiest solution
    is to filter them here.

Arguments:

    String - Supplies a pointer to a location where the string is to be stored.

    StringLength - Supplies the Max Length to read.

    InitialString - Supplies an optional initial string.

    CurrentRow - Supplies the current screen row.

    CurrentColumn - Supplies the current screen column.

    ShowTheTime		If true, the time is displayed in the upper
                        right-hand corner of the screen.

Return Value:

    If the string was successfully obtained GetStringSuccess is return,
    otherwise one of the following codes is returned.

    GetStringEscape - the escape key was pressed or StringLength was reached.
    GetStringUpArrow - the up arrow key was pressed.
    GetStringDownArrow - the down arrow key was pressed.

--*/

{
    ARC_STATUS Status;
    UCHAR c;
    ULONG Count;
    PCHAR Buffer;
    PCHAR Cursor;
    PCHAR CopyPointer;
    GETSTRING_ACTION Action;

    //
    // If an initial string was supplied, update the output string.
    //

    if (ARGUMENT_PRESENT(InitialString)) {
        strcpy(String, InitialString);
        Buffer = strchr(String, 0);
    } else {
        *String = 0;
        Buffer = String;
    }

    Cursor = Buffer;

    while (TRUE) {

        //
        // Print the string.
        //

        VenSetPosition(CurrentRow, CurrentColumn);
        VenPrint(String);
        VenPrint("\x9bK");

        //
        // Print the cursor.
        //

        VenSetScreenAttributes(TRUE,FALSE,TRUE);
        VenSetPosition(CurrentRow, (Cursor - String) + CurrentColumn);

        if (Cursor >= Buffer) {
            VenPrint(" ");
        } else {
            ArcWrite(ARC_CONSOLE_OUTPUT,Cursor,1,&Count);
        }
        VenSetScreenAttributes(TRUE,FALSE,FALSE);

#ifndef JNUPDATE
        while (ShowTheTime &&
	       ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
            JzShowTime(FALSE);
        }
#endif
        Status = ArcRead(ARC_CONSOLE_INPUT,&c,1,&Count);

        if (Status != ESUCCESS) {
            Action = GetStringEscape;
            goto EndGetString;
        }

        if (Buffer-String == StringLength) {
            Action = GetStringEscape;
            goto EndGetString;
        }

        switch (c) {

        case ASCII_ESC:

            //
            // If there is another character available, look to see if
            // this a control sequence, and fall through to ASCII_CSI.
            // This is an attempt to make escape sequences from a terminal work.
            //

            VenStallExecution(10000);

            if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
                ArcRead(ARC_CONSOLE_INPUT, &c, 1, &Count);
                if (c != '[') {
                    Action = GetStringEscape;
                    goto EndGetString;
                }
            } else {
                Action = GetStringEscape;
                goto EndGetString;
            }

        case ASCII_CSI:

            ArcRead(ARC_CONSOLE_INPUT, &c, 1, &Count);
            switch (c) {

            case 'A':
                Action = GetStringUpArrow;
                goto EndGetString;

            case 'D':
                if (Cursor != String) {
                    Cursor--;
                }
                continue;

            case 'B':
                Action = GetStringDownArrow;
                goto EndGetString;

            case 'C':
                if (Cursor != Buffer) {
                    Cursor++;
                }
                continue;

            case 'H':
                Cursor = String;
                continue;

            case 'K':
                Cursor = Buffer;
                continue;

            case 'P':
                CopyPointer = Cursor;
                while (*CopyPointer) {
                    *CopyPointer = *(CopyPointer + 1);
                    CopyPointer++;
                }
                if (Buffer != String) {
                    Buffer--;
                }
                continue;

            default:
                break;
            }
            break;

        case '\r':
        case '\n':

            Action = GetStringSuccess;
            goto EndGetString;

	    //
	    // Do not bother handling the tab character properly.
	    //

	case '\t' :

            Action = GetStringEscape;
            goto EndGetString;

        case '\b':

            if (Cursor != String) {
                Cursor--;
            }
            CopyPointer = Cursor;
            while (*CopyPointer) {
                *CopyPointer = *(CopyPointer + 1);
                CopyPointer++;
            }
            if (Buffer != String) {
                Buffer--;
            }
            break;

	    //
	    // Discard any semicolons because they will corrupt multi-
	    // segment environment variables.
	    //

	case ';':

	    break;

        default:

            //
            // Store the character.
            //

            CopyPointer = ++Buffer;
            if (CopyPointer > Cursor) {
                while (CopyPointer != Cursor) {
                    *CopyPointer = *(CopyPointer - 1);
                    CopyPointer--;
                }
            }
            *Cursor++ = c;
            break;
        }
    }

    Action = GetStringEscape;

EndGetString:

    VenSetPosition(CurrentRow, (Cursor - String) + CurrentColumn);

    if (Cursor >= Buffer) {
        VenPrint(" ");
    } else {
        ArcWrite(ARC_CONSOLE_OUTPUT,Cursor,1,&Count);
    }

    //
    // Make sure we return a null string if not successful.
    //

    if (Action != GetStringSuccess) {
        *String = 0;
    }

    return(Action);
}
예제 #12
0
//
// standard printf function with a subset of formating features supported.
//
// supported
//	%d, %ld - signed short, signed long
//	%u, %lu - unsigned short, unsigned long
//	%c, %s  - character, string
//	%x, %lx - unsigned print in hex, unsigned long print in hex
//	%wS,%wZ	- unicode string
//
//	does not do:
//
//	- field width specification
//	- floating point.
//
VOID BlPrint(__in PCHAR cp,...)
{
	PVOID ap											= Add2Ptr(&cp,sizeof(PCHAR),PVOID);
	USHORT b											= 0;
	ULONG Count											= 0;
	ULONG DeviceId										= BlConsoleOutDeviceId ? BlConsoleOutDeviceId : 1;

	while(b = *cp ++)
	{
		if(b == '%')
		{
			USHORT c									= *cp ++;
			switch(c)
			{
			case 'c':
				ArcWrite(DeviceId,ap,sizeof(UCHAR),&Count);
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'd':
				puti(*static_cast<PLONG>(ap));
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'l':
				{
					USHORT d							= *cp ++;
					switch(d)
					{
					case 'd':
						puti(*static_cast<PLONG>(ap));
						ap								= Add2Ptr(ap,sizeof(LONG),PVOID);
						break;

					case 'u':
						putu(*static_cast<PUSHORT>(ap));
						ap								= Add2Ptr(ap,sizeof(LONG),PVOID);
						break;

					case 'x':
						{
							ULONG x						= *static_cast<PULONG>(ap);
							ULONG ZeroLength			= (x < 0x10) + (x < 0x100) + (x < 0x1000) + (x < 0x10000) + (x < 0x100000) + (x < 0x1000000) + (x < 0x10000000);
							while(ZeroLength --)
								ArcWrite(DeviceId,"0",sizeof(UCHAR),&Count);
							putx(x);
							ap							= Add2Ptr(ap,sizeof(LONG),PVOID);
						}
						break;
					}
				}
				break;

			case 's':
				{
					PCHAR String						= *static_cast<PCHAR*>(ap);
					ArcWrite(DeviceId,String,strlen(String),&Count);
					ap									= Add2Ptr(ap,sizeof(PCHAR),PVOID);
				}
				break;

			case 'u':
				putu(*static_cast<PUSHORT>(ap));
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'w':
				{
					USHORT d							= *cp ++;
					switch(d)
					{
					case 'S':
					case 'W':
						putwS(*static_cast<PUNICODE_STRING*>(ap));
						ap								= Add2Ptr(ap,sizeof(PUNICODE_STRING),PVOID);
						break;
					}
				}
				break;

			case 'x':
				{
					USHORT x							= *static_cast<PUSHORT>(ap);
					ULONG ZeroLength					= (x < 0x10) + (x < 0x100) + (x < 0x1000);
					while(ZeroLength --)
						ArcWrite(DeviceId,"0",sizeof(UCHAR),&Count);
					putx(x);
					ap									= Add2Ptr(ap,sizeof(LONG),PVOID);
				}
				break;

			default:
				ArcWrite(DeviceId,&b,sizeof(UCHAR),&Count);
				ArcWrite(DeviceId,&c,sizeof(UCHAR),&Count);
				break;
			}
		}
		else
		{
			if(!DbcsLangId || !GrIsDBCSLeadByte(cp[-1]))
			{
				ArcWrite(DeviceId,cp - 1,1,&Count);
			}
			else
			{
				ArcWrite(DeviceId,cp - 1,2,&Count);
				cp										+= 1;
			}
		}
	}
}
예제 #13
0
VOID
SlpDrawMenuItem(
    IN ULONG X,
    IN ULONG Y,
    IN ULONG TopItem,
    IN ULONG Height,
    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

    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;
    CHAR 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
    }

    RtlFillMemory(Width,Menu->Width,' ');
    RtlCopyMemory(Width,MenuItem->Text,strlen(MenuItem->Text));
    SlPositionCursor(X+2, Y+(Item-TopItem)+1);
    ArcWrite(ARC_CONSOLE_OUTPUT,Width,Menu->Width,&Count);
}
예제 #14
0
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;
    CHAR 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,&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++) {
        RtlFillMemory(Output+1,MenuWidth-2,' ');
        SlPositionCursor(X, i);

        if (&Item->ListEntry != &Menu->ItemListHead) {
            Length = strlen(Item->Text);
            RtlCopyMemory(Output+2,Item->Text,Length);
            Item = CONTAINING_RECORD(Item->ListEntry.Flink,
                                     SL_MENUITEM,
                                     ListEntry);
        }
        ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth,&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,&Count);
}
예제 #15
0
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;
    PCHAR Header;
    ULONG HeaderLines;
    ULONG MaxHeaderLength;
    PCHAR HeaderText[20];
    ULONG HeaderLength[20];
    ULONG MaxMenuHeight;
    ULONG i;
    ULONG Count;

    Header = BlFindMessage(HeaderId);

    SlpSizeMessage(Header,
                   &HeaderLines,
                   &MaxHeaderLength,
                   HeaderLength,
                   HeaderText);

    X = (ScreenWidth-MaxHeaderLength)/2;
    for (i=0;i<HeaderLines;i++) {
        SlPositionCursor(X,i+4);
        ArcWrite(ARC_CONSOLE_OUTPUT,HeaderText[i],HeaderLength[i],&Count);
    }

    if (MaxHeaderLength > ScreenWidth) {
        MaxHeaderLength = ScreenWidth;
    }

    Width = Menu->Width+4;
    if (Width > ScreenWidth) {
        Width=ScreenWidth;
    }

    MaxMenuHeight = ScreenHeight-(HeaderLines+13);

    Height = Menu->ItemCount+2;
    if (Height > MaxMenuHeight) {
        Height = MaxMenuHeight;
    }

    X = ((ScreenWidth - Width)/2 > 0) ? (ScreenWidth-Width)/2 : 0;
    Y = (MaxMenuHeight - Height)/2 + HeaderLines + 4;

    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,
                Height,
                Sel,
                Menu);
    SlSetCurrentAttribute(DEFATT);
    SlFlushConsoleBuffer();
    do {
        c = SlGetChar();
        PreviousSelection = Sel;
        SlpDrawMenuItem(X, Y,
                    TopItem,
                    Height,
                    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;
                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,
                    Height,
                    Sel,
                    Menu);
        SlSetCurrentAttribute(DEFATT);


    } while ( TRUE );

}
예제 #16
0
VOID
SlGenericMessageBox(
    IN     ULONG   MessageId, OPTIONAL
    IN     va_list *args,     OPTIONAL
    IN     PCHAR   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.

--*/

{
    PCHAR p;
    ULONG NumLines;
    ULONG MaxLength;
    ULONG x;
    ULONG y;
    ULONG i;
    PCHAR Line[20];
    ULONG LineLength[20];
    ULONG Count;

    if(!Message) {    // then look up the message
        p=BlFindMessage(MessageId);
        if (p==NULL) {
            SlError(MessageId);
            x=3;
            y=ScreenHeight/2;
            NumLines=0;
        } else {
            _vsnprintf(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("");  // 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],&Count);
    }

    if(xLeft) {
        *xLeft = x;
    }

    if(yTop) {
        *yTop = y;
    }

    if(yBottom) {
        *yBottom = NumLines ? y+NumLines-1 : 0;
    }
}