Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. arcdisp.c
  5. Abstract:
  6. This module provides code for managing screen output on an ARC-compliant
  7. system.
  8. Author:
  9. John Vert (jvert) 6-Oct-1993
  10. Revision History:
  11. John Vert (jvert) 6-Oct-1993
  12. Taken from old 1.0 splib sources
  13. --*/
  14. #include "setupldr.h"
  15. #include "parseini.h"
  16. #include "stdio.h"
  17. #include "hdlsterm.h"
  18. #ifdef i386
  19. #include "bldrx86.h"
  20. #endif
  21. #if defined(_IA64_)
  22. #include "bldria64.h"
  23. #endif
  24. #if defined(EFI)
  25. #include "bootefi.h"
  26. #endif
  27. //
  28. // The screen is divided into 3 areas: the header area, the status area,
  29. // and the client area. The header area basically always says "Windows NT
  30. // Setup". The status area is always 1 line high and displayed using a
  31. // different attribute (black on gray).
  32. //
  33. #define HEADER_HEIGHT 3
  34. #define MAX_STATUS 200 // allow up to 1600 horizontal res.
  35. #define SCREEN_SIZE (ScreenWidth*ScreenHeight)
  36. BOOLEAN StatusBarEnabled = TRUE;
  37. ULONG ScreenWidth=80;
  38. ULONG ScreenHeight=25;
  39. ULONG ScreenX=0,ScreenY=0;
  40. UCHAR CurAttribute = (ATT_FG_WHITE | ATT_BG_BLACK);
  41. TCHAR MessageBuffer[1024];
  42. extern BOOLEAN ShowProgressBar;
  43. //
  44. // private function prototypes
  45. //
  46. VOID
  47. SlpDrawMenu(
  48. IN ULONG X,
  49. IN ULONG Y,
  50. IN ULONG TopItem,
  51. IN ULONG Height,
  52. IN PSL_MENU Menu
  53. );
  54. VOID
  55. SlpDrawMenuItem(
  56. IN ULONG X,
  57. IN ULONG Y,
  58. IN ULONG TopItem,
  59. IN ULONG Item,
  60. IN PSL_MENU Menu
  61. );
  62. VOID
  63. SlpSizeMessage(
  64. IN PTCHAR Message,
  65. OUT PULONG Lines,
  66. OUT PULONG MaxLength,
  67. OUT ULONG LineLength[],
  68. OUT PTCHAR LineText[]
  69. );
  70. PSL_MENU
  71. SlCreateMenu(
  72. VOID
  73. )
  74. /*++
  75. Routine Description:
  76. Allocates and initializes a new menu structure.
  77. Arguments:
  78. None
  79. Return Value:
  80. Pointer to the new menu structure if successful.
  81. NULL on failure
  82. --*/
  83. {
  84. PSL_MENU p;
  85. p=BlAllocateHeap(sizeof(SL_MENU));
  86. if (p==NULL) {
  87. return(NULL);
  88. }
  89. p->ItemCount = 0;
  90. p->Width = 0;
  91. InitializeListHead(&p->ItemListHead);
  92. return(p);
  93. }
  94. BOOLEAN
  95. SlGetMenuItemIndex(
  96. IN PSL_MENU Menu,
  97. IN PTCHAR Text,
  98. OUT PULONG Index
  99. )
  100. /*++
  101. Routine Description:
  102. Given the text of a menu item, returns the index of that item.
  103. Arguments:
  104. Menu - Supplies the menu
  105. Text - Supplies the text to search for.
  106. Index - Returns the index of the text in the menu
  107. Return Value:
  108. TRUE - Item was found.
  109. FALSE - Item was not found
  110. --*/
  111. {
  112. ULONG i;
  113. PSL_MENUITEM Item;
  114. //
  115. // Find first item to display
  116. //
  117. Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
  118. SL_MENUITEM,
  119. ListEntry);
  120. i=0;
  121. while ( Item != CONTAINING_RECORD(&Menu->ItemListHead,
  122. SL_MENUITEM,
  123. ListEntry)) {
  124. if (_tcsicmp(Item->Text,Text)==0) {
  125. *Index = i;
  126. return(TRUE);
  127. }
  128. Item = CONTAINING_RECORD(Item->ListEntry.Flink,
  129. SL_MENUITEM,
  130. ListEntry);
  131. ++i;
  132. }
  133. return(FALSE);
  134. }
  135. PVOID
  136. SlGetMenuItem(
  137. IN PSL_MENU Menu,
  138. IN ULONG Item
  139. )
  140. /*++
  141. Routine Description:
  142. Given an item index, returns the data associated with that item.
  143. Arguments:
  144. Menu - Supplies the menu structure.
  145. Item - Supplies the item index.
  146. Return Value:
  147. The data associated with the given item.
  148. --*/
  149. {
  150. ULONG i;
  151. PSL_MENUITEM MenuItem;
  152. //
  153. // Find item to return
  154. //
  155. MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
  156. SL_MENUITEM,
  157. ListEntry);
  158. for (i=0;i<Item;i++) {
  159. MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
  160. SL_MENUITEM,
  161. ListEntry);
  162. #if DBG
  163. if (&MenuItem->ListEntry == &Menu->ItemListHead) {
  164. SlError(Item);
  165. return(NULL);
  166. }
  167. #endif
  168. }
  169. return(MenuItem->Data);
  170. }
  171. ULONG
  172. SlAddMenuItem(
  173. PSL_MENU Menu,
  174. PTCHAR Text,
  175. PVOID Data,
  176. ULONG Attributes
  177. )
  178. /*++
  179. Routine Description:
  180. Adds an item to the menu
  181. Arguments:
  182. Menu - Supplies a pointer to the menu the item will be added to
  183. Text - Supplies the text to be displayed in the menu
  184. Data - Supplies a pointer to the data to be returned when the item
  185. is selected.
  186. Attributes - Supplies any attributes for the item.
  187. Return Value:
  188. The Selection index if successful
  189. -1 on failure
  190. --*/
  191. {
  192. PSL_MENUITEM NewItem;
  193. ULONG Length;
  194. NewItem = BlAllocateHeap(sizeof(SL_MENUITEM));
  195. if (NewItem==NULL) {
  196. SlError(0);
  197. return((ULONG)-1);
  198. }
  199. InsertTailList(&Menu->ItemListHead, &NewItem->ListEntry);
  200. Menu->ItemCount += 1;
  201. NewItem->Text = Text;
  202. NewItem->Data = Data;
  203. NewItem->Attributes = Attributes;
  204. Length = (ULONG)_tcslen(Text);
  205. if (Length > Menu->Width) {
  206. Menu->Width = Length;
  207. }
  208. return(Menu->ItemCount - 1);
  209. }
  210. ULONG
  211. SlDisplayMenu(
  212. IN ULONG HeaderId,
  213. IN PSL_MENU Menu,
  214. IN OUT PULONG Selection
  215. )
  216. /*++
  217. Routine Description:
  218. Displays a menu and allows the user to pick a selection
  219. Arguments:
  220. HeaderId - Supplies the message ID of the prompt header
  221. to be displayed above the menu.
  222. Menu - Supplies a pointer to the menu to be displayed
  223. Selection - Supplies the index of the default item.
  224. Returns the index of the selected item.
  225. Return Value:
  226. Key that terminated the menu display.
  227. --*/
  228. {
  229. LONG X, Y;
  230. ULONG Height;
  231. ULONG Width;
  232. ULONG TopItem;
  233. ULONG c;
  234. ULONG PreviousSelection;
  235. ULONG Sel;
  236. PTCHAR Header;
  237. ULONG HeaderLines;
  238. ULONG MaxHeaderLength;
  239. PTCHAR HeaderText[20];
  240. ULONG HeaderLength[20];
  241. ULONG MaxMenuHeight;
  242. ULONG i;
  243. ULONG Count;
  244. Header = BlFindMessage(HeaderId);
  245. SlpSizeMessage(Header,
  246. &HeaderLines,
  247. &MaxHeaderLength,
  248. HeaderLength,
  249. HeaderText);
  250. if (MaxHeaderLength > ScreenWidth) {
  251. MaxHeaderLength = ScreenWidth;
  252. }
  253. X = (ScreenWidth-MaxHeaderLength)/2;
  254. for (i=0;i<HeaderLines;i++) {
  255. SlPositionCursor(X,i+4);
  256. ArcWrite(ARC_CONSOLE_OUTPUT,HeaderText[i],HeaderLength[i]*sizeof(TCHAR),&Count);
  257. }
  258. Width = Menu->Width+4;
  259. if (Width > ScreenWidth) {
  260. Width=ScreenWidth;
  261. }
  262. //
  263. // HEADER_HEIGHT + 1 line separator + text height + 1 line separator + max menu heigth +
  264. // + 1 line separator + 1 line status bar = screen height
  265. //
  266. MaxMenuHeight = ScreenHeight-(HeaderLines+HEADER_HEIGHT+4);
  267. Height = Menu->ItemCount+2;
  268. if (Height > MaxMenuHeight) {
  269. Height = MaxMenuHeight;
  270. }
  271. X = (ScreenWidth-Width)/2;
  272. Y = (MaxMenuHeight - Height)/2 + HeaderLines + HEADER_HEIGHT + 2;
  273. TopItem = 0;
  274. Sel = *Selection;
  275. //
  276. // Make sure default item is in view;
  277. //
  278. if (Sel >= Height - 2) {
  279. TopItem = Sel - Height + 3;
  280. }
  281. SlpDrawMenu(X,Y,
  282. TopItem,
  283. Height,
  284. Menu);
  285. //
  286. // highlight default selection
  287. //
  288. SlSetCurrentAttribute(INVATT);
  289. SlpDrawMenuItem(X,Y,
  290. TopItem,
  291. Sel,
  292. Menu);
  293. SlSetCurrentAttribute(DEFATT);
  294. SlFlushConsoleBuffer();
  295. #ifdef EFI
  296. //
  297. // disable efi watchdog timer
  298. //
  299. DisableEFIWatchDog();
  300. #endif
  301. do {
  302. c = SlGetChar();
  303. PreviousSelection = Sel;
  304. SlpDrawMenuItem(X, Y,
  305. TopItem,
  306. Sel,
  307. Menu);
  308. switch (c) {
  309. case SL_KEY_UP:
  310. if(Sel > 0) {
  311. Sel--;
  312. }
  313. break;
  314. case SL_KEY_DOWN:
  315. if(Sel < Menu->ItemCount - 1) {
  316. Sel++;
  317. }
  318. break;
  319. case SL_KEY_HOME:
  320. Sel = 0;
  321. break;
  322. case SL_KEY_END:
  323. Sel = Menu->ItemCount - 1;
  324. break;
  325. case SL_KEY_PAGEUP:
  326. if (Menu->ItemCount > Height) {
  327. if (Sel > Height) {
  328. Sel -= Height;
  329. } else {
  330. Sel = 0;
  331. }
  332. }
  333. break;
  334. case SL_KEY_PAGEDOWN:
  335. if (Menu->ItemCount > Height) {
  336. Sel += Height;
  337. if (Sel >= Menu->ItemCount) {
  338. Sel = Menu->ItemCount - 1;
  339. }
  340. }
  341. break;
  342. case SL_KEY_F1:
  343. case SL_KEY_F3:
  344. case ASCI_CR:
  345. case ASCI_ESC:
  346. *Selection = Sel;
  347. #ifdef EFI
  348. //
  349. // reset efi watchdog
  350. //
  351. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  352. #endif
  353. return(c);
  354. }
  355. if (Sel < TopItem) {
  356. TopItem = Sel;
  357. SlpDrawMenu(X, Y,
  358. TopItem,
  359. Height,
  360. Menu);
  361. } else if (Sel > TopItem+Height-3) {
  362. TopItem = Sel - Height + 3;
  363. SlpDrawMenu(X, Y,
  364. TopItem,
  365. Height,
  366. Menu);
  367. }
  368. //
  369. // highlight default selection
  370. //
  371. SlSetCurrentAttribute(INVATT);
  372. SlpDrawMenuItem(X,Y,
  373. TopItem,
  374. Sel,
  375. Menu);
  376. SlSetCurrentAttribute(DEFATT);
  377. } while ( TRUE );
  378. }
  379. VOID
  380. SlpDrawMenu(
  381. IN ULONG X,
  382. IN ULONG Y,
  383. IN ULONG TopItem,
  384. IN ULONG Height,
  385. IN PSL_MENU Menu
  386. )
  387. /*++
  388. Routine Description:
  389. Displays the menu on the screen
  390. Arguments:
  391. X - Supplies X coordinate of upper-left corner of menu
  392. Y - Supplies Y coordinate of upper-left corner of menu
  393. TopItem - Supplies index of item at the top of the menu
  394. Height - Supplies the height of the menu
  395. Menu - Supplies the menu to be displayed
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. ULONG i;
  401. PSL_MENUITEM Item;
  402. ULONG Count;
  403. TCHAR Output[80];
  404. ULONG Length;
  405. ULONG MenuWidth;
  406. MenuWidth = Menu->Width+4;
  407. Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleDown);
  408. for (i=1;i<MenuWidth-1;i++) {
  409. Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
  410. }
  411. Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleDown);
  412. SlPositionCursor(X,Y);
  413. ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
  414. //
  415. // Find first item to display
  416. //
  417. Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
  418. SL_MENUITEM,
  419. ListEntry);
  420. for (i=0;i<TopItem;i++) {
  421. Item = CONTAINING_RECORD(Item->ListEntry.Flink,
  422. SL_MENUITEM,
  423. ListEntry);
  424. }
  425. //
  426. // Display items
  427. //
  428. Output[0]=
  429. Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleVertical);
  430. for (i=Y+1;i<Y+Height-1;i++) {
  431. #ifdef UNICODE
  432. for (Count = 0 ; Count < MenuWidth-2;Count++) {
  433. Output[1+Count] = TEXT(' ');
  434. }
  435. #else
  436. RtlFillMemory(Output+1,(MenuWidth-2)*sizeof(TCHAR),' ');
  437. #endif
  438. SlPositionCursor(X, i);
  439. if (&Item->ListEntry != &Menu->ItemListHead) {
  440. Length = (ULONG)_tcslen(Item->Text);
  441. if (Menu->Width < Length) {
  442. Length = Menu->Width;
  443. }
  444. RtlCopyMemory(Output+2,Item->Text,Length*sizeof(TCHAR));
  445. Item = CONTAINING_RECORD(Item->ListEntry.Flink,
  446. SL_MENUITEM,
  447. ListEntry);
  448. }
  449. ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
  450. }
  451. Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleUp);
  452. for (i=1;i<MenuWidth-1;i++) {
  453. Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
  454. }
  455. Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleUp);
  456. SlPositionCursor(X,Y+Height-1);
  457. ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth*sizeof(TCHAR),&Count);
  458. }
  459. VOID
  460. SlpDrawMenuItem(
  461. IN ULONG X,
  462. IN ULONG Y,
  463. IN ULONG TopItem,
  464. IN ULONG Item,
  465. IN PSL_MENU Menu
  466. )
  467. /*++
  468. Routine Description:
  469. Redraws the given item
  470. Arguments:
  471. X - Supplies X coordinate of upper-left corner of menu
  472. Y - Supplies Y coordinate of upper-left corner of menu
  473. TopItem - Supplies index of item at the top of the menu
  474. Height - Supplies the height of the menu
  475. - We had been passing in the Menu Height. But we have no use for
  476. - it, since we are already assuming that the menu item id exists,
  477. - so therefore we are writing exactly one line.
  478. Item - Supplies the index of the item to be redrawn
  479. Menu - Supplies the menu to be displayed
  480. Return Value:
  481. None.
  482. --*/
  483. {
  484. ULONG i;
  485. PSL_MENUITEM MenuItem;
  486. ULONG Count;
  487. TCHAR Width[80];
  488. //
  489. // Find item to display
  490. //
  491. MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
  492. SL_MENUITEM,
  493. ListEntry);
  494. for (i=0;i<Item;i++) {
  495. MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
  496. SL_MENUITEM,
  497. ListEntry);
  498. #if DBG
  499. if (&MenuItem->ListEntry == &Menu->ItemListHead) {
  500. SlError(Item);
  501. }
  502. #endif
  503. }
  504. #ifdef UNICODE
  505. for (Count = 0 ; Count < Menu->Width;Count++) {
  506. Width[Count] = TEXT(' ');
  507. }
  508. #else
  509. RtlFillMemory(Width,(Menu->Width)*sizeof(TCHAR),' ');
  510. #endif
  511. RtlCopyMemory(
  512. Width,
  513. MenuItem->Text,
  514. _tcslen(MenuItem->Text)*sizeof(TCHAR) );
  515. SlPositionCursor(X+2, Y+(Item-TopItem)+1);
  516. ArcWrite(ARC_CONSOLE_OUTPUT,Width,Menu->Width*sizeof(TCHAR),&Count);
  517. }
  518. VOID
  519. SlInitDisplay(
  520. VOID
  521. )
  522. /*++
  523. Routine Description:
  524. Clears the screen and does some initialization of global variables based
  525. on the ARC display information.
  526. Arguments:
  527. None
  528. Return Value:
  529. None.
  530. --*/
  531. {
  532. #ifndef EFI
  533. PARC_DISPLAY_STATUS DisplayStatus;
  534. //
  535. // Check to see if this version of the ARC firmware is revision 2 or above.
  536. //
  537. // If not, we default to 80x25
  538. //
  539. if ((SYSTEM_BLOCK->Version > 1) ||
  540. ((SYSTEM_BLOCK->Version == 1) && (SYSTEM_BLOCK->Revision >= 2))) {
  541. //
  542. // Additional checks are required on 1.2 firmware, since some
  543. // 1.2 firmware does not implement ArcGetDisplayStatus
  544. //
  545. if ((SYSTEM_BLOCK->FirmwareVectorLength > (ULONG)GetDisplayStatusRoutine*sizeof(PVOID)) &&
  546. (SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] != NULL)) {
  547. DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
  548. ScreenWidth = DisplayStatus->CursorMaxXPosition;
  549. ScreenHeight = DisplayStatus->CursorMaxYPosition;
  550. }
  551. }
  552. #ifdef ARCI386
  553. SlPrint(ASCI_CSI_OUT "2J"); // Clears Screen
  554. SlSetCurrentAttribute(DEFATT);
  555. //
  556. // This is a patch to setup VGA colors in the text port.
  557. // Otherwise screen colors and attributes are not the same as a PC
  558. //
  559. // Write all the attributes to the textport
  560. {
  561. int row;
  562. TCHAR text[MAX_STATUS+1];
  563. ULONG Count,Length;
  564. _stprintf(text,TEXT(" "));
  565. // 012345678901234567890123456789012345678901234567890123456789012345678901234567890
  566. // 1 2 3 4 5 6 7 8
  567. for (row=0; row< 48; row++) // compensate for the long textport 48 versus 24 (VGA)
  568. ArcWrite(ARC_CONSOLE_OUTPUT,text,strlen(&text[0]),&Count);
  569. }
  570. // Position cursor at Top Left of screen
  571. SlPositionCursor(0,0);
  572. #endif
  573. #endif
  574. #ifdef EFI
  575. //
  576. // On EFI, we won't be redirecting because setupldr.efi is an
  577. // EFI application. If that's the case, then we can't use
  578. // BlIsTerminalConnected(). Instead, we're going to look
  579. // at the values in the LoaderRedirectionInformation structure
  580. // to see if we're really redirecting.
  581. //
  582. if( LoaderRedirectionInformation.PortAddress != 0 ) {
  583. #else
  584. if (BlIsTerminalConnected()) {
  585. #endif
  586. ScreenHeight = HEADLESS_SCREEN_HEIGHT;
  587. }
  588. SlSetCurrentAttribute(DEFATT);
  589. SlClearDisplay();
  590. }
  591. VOID
  592. SlPrint(
  593. IN PTCHAR FormatString,
  594. ...
  595. )
  596. {
  597. va_list arglist;
  598. TCHAR text[MAX_STATUS+1];
  599. ULONG Count,Length;
  600. ULONG MaxWidth = ScreenWidth - 2;
  601. if (MaxWidth > MAX_STATUS) {
  602. MaxWidth = MAX_STATUS;
  603. }
  604. va_start(arglist,FormatString);
  605. Length = _vsntprintf(text,MaxWidth*sizeof(TCHAR),FormatString,arglist);
  606. text[MaxWidth] = TEXT('\0');
  607. ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count);
  608. va_end(arglist);
  609. }
  610. VOID
  611. SlClearDisplay(
  612. VOID
  613. )
  614. /*++
  615. Routine Description:
  616. Clears the entire display, including header, client area, and status line.
  617. Arguments:
  618. None
  619. Return Value:
  620. None.
  621. --*/
  622. {
  623. #if 1
  624. BlClearScreen();
  625. #else
  626. SlPositionCursor(0,0);
  627. #ifdef EFI
  628. BlEfiClearToEndOfDisplay();
  629. #else
  630. ARC_DISPLAY_CLEAR_TO_EOD();
  631. #endif
  632. if (!ShowProgressBar) {
  633. SlWriteStatusText(TEXT(""));
  634. }
  635. #endif
  636. }
  637. ARC_STATUS
  638. SlClearClientArea(
  639. VOID
  640. )
  641. /*++
  642. Routine Description:
  643. Clears the client area of the screen. Does not disturb the header or
  644. status areas.
  645. Arguments:
  646. None.
  647. Return Value:
  648. always ESUCCESS
  649. --*/
  650. {
  651. USHORT i;
  652. for(i=HEADER_HEIGHT; i<ScreenHeight-1; i++) {
  653. SlPositionCursor(0,i);
  654. SlClearToEol();
  655. }
  656. //
  657. // home cursor
  658. //
  659. SlPositionCursor(0,0);
  660. return(ESUCCESS);
  661. }
  662. ARC_STATUS
  663. SlClearToEol(
  664. VOID
  665. )
  666. {
  667. #ifdef EFI
  668. BlEfiClearToEndOfLine();
  669. #else
  670. ARC_DISPLAY_CLEAR_TO_EOL();
  671. #endif
  672. return(ESUCCESS);
  673. }
  674. VOID
  675. SlGetCursorPosition(
  676. OUT unsigned *x,
  677. OUT unsigned *y
  678. )
  679. {
  680. *x = ScreenX;
  681. *y = ScreenY;
  682. }
  683. ARC_STATUS
  684. SlPositionCursor(
  685. IN unsigned x,
  686. IN unsigned y
  687. )
  688. {
  689. //
  690. // clip to screen
  691. //
  692. if(x>=ScreenWidth) {
  693. x = ScreenWidth-1;
  694. }
  695. if(y>=ScreenHeight) {
  696. y = ScreenHeight-1;
  697. }
  698. ScreenX = x;
  699. ScreenY = y;
  700. #ifdef EFI
  701. BlEfiPositionCursor(x, y );
  702. #else
  703. ARC_DISPLAY_POSITION_CURSOR(x, y);
  704. #endif
  705. return(ESUCCESS);
  706. }
  707. ARC_STATUS
  708. SlWriteString(
  709. IN PTCHAR s
  710. )
  711. {
  712. PTCHAR p = s,q;
  713. BOOLEAN done = FALSE;
  714. ULONG len,count;
  715. do {
  716. q = p;
  717. while((*q != TEXT('\0')) && (*q != TEXT('\n'))) {
  718. q++;
  719. }
  720. if(*q == TEXT('\0')) {
  721. done = TRUE;
  722. } else {
  723. *q = TEXT('\0');
  724. }
  725. len = (ULONG)(q - p);
  726. ArcWrite(ARC_CONSOLE_OUTPUT,p,len*sizeof(TCHAR),&count);
  727. ScreenX += len;
  728. if(!done) {
  729. ArcWrite(ARC_CONSOLE_OUTPUT,TEXT("\r\n"),2*sizeof(TCHAR),&count);
  730. ScreenX = 0;
  731. ScreenY++;
  732. if(ScreenY == ScreenHeight) {
  733. ScreenY = ScreenHeight-1;
  734. }
  735. *q = TEXT('\n');
  736. }
  737. p = q + 1;
  738. } while(!done);
  739. return(ESUCCESS);
  740. }
  741. VOID
  742. SlSetCurrentAttribute(
  743. IN UCHAR Attribute
  744. )
  745. {
  746. CurAttribute = Attribute;
  747. #ifdef EFI
  748. BlEfiSetAttribute( CurAttribute );
  749. #else
  750. SlPrint(ASCI_CSI_OUT);
  751. if (BlIsTerminalConnected() &&
  752. ((Attribute == DEFSTATTR) ||
  753. (Attribute == INVATT))) {
  754. SlPrint(TEXT("7"));
  755. } else {
  756. SlPrint(TEXT("0"));
  757. }
  758. SlPrint(TEXT(";%u;%um"), (Attribute & 0x7) + 30, ((Attribute >> 4) & 7) + 40);
  759. if(Attribute & ATT_FG_INTENSE) {
  760. SlPrint(ASCI_CSI_OUT TEXT("1m"));
  761. }
  762. #endif
  763. }
  764. VOID
  765. SlWriteHeaderText(
  766. IN ULONG MsgId
  767. )
  768. /*++
  769. Routine Description:
  770. Updates the header on the screen with a given string
  771. Arguments:
  772. MsgId - Supplies the message ID of the new string to be displayed. This should
  773. be just one line long. If it is 0, the header is cleared.
  774. Return Value:
  775. None.
  776. --*/
  777. {
  778. int i;
  779. for(i=HEADER_HEIGHT-1; i>=0; i--) {
  780. SlPositionCursor(0,i);
  781. SlClearToEol();
  782. }
  783. if (MsgId != 0) {
  784. SlWriteString(BlFindMessage(MsgId));
  785. }
  786. }
  787. //
  788. // Stores the current status text. The size is the screen width, plus the
  789. // terminating nul char.
  790. //
  791. TCHAR StatusText[MAX_STATUS];
  792. UCHAR StatusAttribute = DEFSTATTR;
  793. VOID
  794. SlSetStatusAttribute(
  795. IN UCHAR Attribute
  796. )
  797. {
  798. StatusAttribute = Attribute;
  799. }
  800. BOOLEAN
  801. SlGetStatusBarStatus(
  802. VOID
  803. )
  804. /*++
  805. Routine Description:
  806. Determines if status bar is enabled or not
  807. Arguments:
  808. None.
  809. Return Value:
  810. TRUE or FALSE
  811. --*/
  812. {
  813. return StatusBarEnabled;
  814. }
  815. VOID
  816. SlEnableStatusBar(
  817. IN BOOLEAN Enable
  818. )
  819. /*++
  820. Routine Description:
  821. Enables or disables the status bar
  822. Arguments:
  823. Enabled - Enable/Disable = TRUE/FALSE
  824. Return Value:
  825. None.
  826. --*/
  827. {
  828. StatusBarEnabled = Enable;
  829. }
  830. VOID
  831. SlWriteStatusText(
  832. IN PTCHAR Text
  833. )
  834. /*++
  835. Routine Description:
  836. Updates the status area on the screen with a given string
  837. Arguments:
  838. Text - Supplies the new text for the status area.
  839. Return Value:
  840. None.
  841. --*/
  842. {
  843. UCHAR AttributeSave = CurAttribute;
  844. PTCHAR p;
  845. ULONG Count;
  846. #ifdef EFI
  847. ULONG MaxWidth = ScreenWidth - 3;
  848. #else
  849. ULONG MaxWidth = ScreenWidth - 2;
  850. #endif
  851. //
  852. // Nop, if status bar is disabled
  853. //
  854. if (!StatusBarEnabled) {
  855. return;
  856. }
  857. //
  858. // if we're writing to a terminal, we don't want to write into the lower
  859. // right corner as this would make us scroll.
  860. //
  861. if (BlTerminalConnected) {
  862. MaxWidth -= 1;
  863. }
  864. if (MaxWidth > MAX_STATUS) {
  865. MaxWidth = MAX_STATUS;
  866. }
  867. #ifdef UNICODE
  868. for (Count = 0 ; Count < sizeof(StatusText)/sizeof(TCHAR);Count++) {
  869. StatusText[Count] = TEXT(' ');
  870. }
  871. #else
  872. RtlFillMemory(StatusText,sizeof(StatusText),' ');
  873. #endif
  874. //
  875. // Strip cr/lf as we copy the status text into the status text buffer.
  876. //
  877. p = StatusText;
  878. Count = 0;
  879. while((Count < MaxWidth) && *Text) {
  880. if((*Text != TEXT('\r')) && (*Text != TEXT('\n'))) {
  881. *p++ = *Text;
  882. Count++;
  883. }
  884. Text++;
  885. }
  886. SlSetCurrentAttribute(StatusAttribute);
  887. SlPositionCursor(0,ScreenHeight-1);
  888. ArcWrite(ARC_CONSOLE_OUTPUT,TEXT(" "),2*sizeof(TCHAR),&Count);
  889. SlPositionCursor(2,ScreenHeight-1);
  890. ArcWrite(ARC_CONSOLE_OUTPUT,StatusText,MaxWidth*sizeof(TCHAR),&Count);
  891. SlSetCurrentAttribute(AttributeSave);
  892. SlPositionCursor(0,5);
  893. }
  894. VOID
  895. SlGetStatusText(
  896. OUT PTCHAR Text
  897. )
  898. {
  899. _tcscpy(Text,StatusText);
  900. }
  901. #if DBG
  902. VOID
  903. SlWriteDbgText(
  904. IN PTCHAR text
  905. )
  906. {
  907. UCHAR SavedAttribute = CurAttribute;
  908. SlPositionCursor(0,0);
  909. CurAttribute = ATT_FG_YELLOW | ATT_BG_RED | ATT_FG_INTENSE;
  910. SlClearToEol();
  911. SlWriteString(text);
  912. CurAttribute = SavedAttribute;
  913. }
  914. #endif
  915. VOID
  916. SlFlushConsoleBuffer(
  917. VOID
  918. )
  919. /*++
  920. Routine Description:
  921. This routine flushes the console buffer, so that we don't have any
  922. pre-existing keypresses in the buffer when we prompt the user to
  923. 'press any key to continue.'
  924. Arguments:
  925. NONE
  926. Return Value:
  927. NONE
  928. --*/
  929. {
  930. UCHAR c;
  931. ULONG count;
  932. while(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  933. ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
  934. }
  935. }
  936. ULONG
  937. SlGetChar(
  938. VOID
  939. )
  940. {
  941. UCHAR c;
  942. ULONG count;
  943. ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
  944. if(c == ASCI_CSI_IN) {
  945. if (ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
  946. //
  947. // Just a single escape - return it
  948. //
  949. return (ASCI_ESC);
  950. }
  951. ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
  952. switch(c) {
  953. //
  954. // see ntos\fw\mips\fwsignal.c!TranslateScanCode() for these codes.
  955. // Additional codes that might be useful someday:
  956. // left=C, right=D, insert=@, delete=P
  957. //
  958. case 'A': // up arrow
  959. return(SL_KEY_UP);
  960. case 'B': // down arrow
  961. return(SL_KEY_DOWN);
  962. case 'H': // home
  963. return(SL_KEY_HOME);
  964. case 'K': // end
  965. return(SL_KEY_END);
  966. case '?': // page up
  967. return(SL_KEY_PAGEUP);
  968. case '/': // page down
  969. return(SL_KEY_PAGEDOWN);
  970. case 'O': // function keys
  971. ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
  972. //
  973. // F1=P, F2=Q, F3=w, F4 =x, F5 =t, F6 =u
  974. // F7=q, F8=r, F9=p, F10=m, F11=A, F12=B
  975. //
  976. // Note: as of 12/15/92, f11 and f12 were commented out in the
  977. // firmware sources so are probably never returned.
  978. //
  979. switch(c) {
  980. case 'P':
  981. return(SL_KEY_F1);
  982. case 'Q':
  983. return(SL_KEY_F2);
  984. case 'w':
  985. return(SL_KEY_F3);
  986. case 'x':
  987. return(SL_KEY_F4);
  988. case 't':
  989. return(SL_KEY_F5);
  990. case 'u':
  991. return(SL_KEY_F6);
  992. case 'q':
  993. return(SL_KEY_F7);
  994. case 'r':
  995. return SL_KEY_F8;
  996. case 'm':
  997. case 'M':
  998. return SL_KEY_F10;
  999. case 'A':
  1000. return(SL_KEY_F11);
  1001. case 'B':
  1002. return(SL_KEY_F12);
  1003. default:
  1004. return(0);
  1005. }
  1006. default:
  1007. return(0);
  1008. }
  1009. } else {
  1010. if(c == ASCI_LF) {
  1011. c = ASCI_CR;
  1012. }
  1013. return((ULONG)c);
  1014. }
  1015. }
  1016. BOOLEAN
  1017. SlPromptForDisk(
  1018. IN PTCHAR DiskName,
  1019. IN BOOLEAN IsCancellable
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This routine prompts a user to insert a given diskette #, or to abort the
  1024. Setup process.
  1025. The status line will be erased.
  1026. Arguments:
  1027. DiskName - Supplies the name of the disk to be inserted.
  1028. IsCancellable - Supplies flag indicating whether prompt may be cancelled.
  1029. Return Value:
  1030. TRUE - The user has pressed OK
  1031. FALSE - The user has pressed CANCEL
  1032. --*/
  1033. {
  1034. ULONG msg;
  1035. ULONG y;
  1036. ULONG Key;
  1037. PTCHAR Text;
  1038. PTCHAR PleaseWait;
  1039. ULONG i;
  1040. TCHAR DiskNameDisplayed[81];
  1041. BOOLEAN Repaint=TRUE;
  1042. SlWriteStatusText(TEXT(""));
  1043. if(IsCancellable) {
  1044. msg = SL_NEXT_DISK_PROMPT_CANCELLABLE;
  1045. } else {
  1046. msg = SL_NEXT_DISK_PROMPT;
  1047. }
  1048. Text = BlFindMessage(msg);
  1049. if(Text == NULL) {
  1050. SlError(msg);
  1051. return(FALSE);
  1052. }
  1053. PleaseWait = BlFindMessage(SL_PLEASE_WAIT);
  1054. if(PleaseWait == NULL) {
  1055. SlError(SL_PLEASE_WAIT);
  1056. return(FALSE);
  1057. }
  1058. //
  1059. // Get first line of DiskName and save it in DiskNameDisplayed (limit to 80 chars)
  1060. //
  1061. for(i = 0;
  1062. ((i < 80) && DiskName[i] && (DiskName[i] != TEXT('\r')) && (DiskName[i] != TEXT('\n')));
  1063. i++)
  1064. {
  1065. DiskNameDisplayed[i] = DiskName[i];
  1066. }
  1067. DiskNameDisplayed[i] = TEXT('\0');
  1068. do {
  1069. if (Repaint) {
  1070. SlClearClientArea();
  1071. y = SlDisplayMessageBox(SL_MSG_INSERT_DISK);
  1072. SlPositionCursor((ScreenWidth-i)/2,y+2);
  1073. SlWriteString(DiskNameDisplayed);
  1074. SlWriteStatusText(Text);
  1075. }
  1076. Repaint = FALSE;
  1077. SlFlushConsoleBuffer();
  1078. #ifdef EFI
  1079. //
  1080. // diable EFI watchdog when prompting for user input
  1081. //
  1082. DisableEFIWatchDog();
  1083. #endif
  1084. Key = SlGetChar();
  1085. #ifdef EFI
  1086. //
  1087. // reset EFI watchdog
  1088. //
  1089. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  1090. #endif
  1091. if (Key == ASCI_CR) {
  1092. SlClearClientArea();
  1093. SlWriteStatusText(PleaseWait);
  1094. return(TRUE);
  1095. } else if (Key == SL_KEY_F3) {
  1096. SlConfirmExit();
  1097. Repaint=TRUE;
  1098. } else if((Key == ASCI_ESC) && IsCancellable) {
  1099. SlWriteStatusText(TEXT(""));
  1100. SlClearClientArea();
  1101. return FALSE;
  1102. }
  1103. } while ( TRUE );
  1104. }
  1105. VOID
  1106. SlConfirmExit(
  1107. VOID
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Routine to be called when user presses F3. Confirms that he really wants
  1112. to exit by popping up a dialog. DOES NOT RETURN if user chooses to exit.
  1113. Arguments:
  1114. None.
  1115. Return Value:
  1116. None.
  1117. --*/
  1118. {
  1119. ULONG c;
  1120. //
  1121. // if we use too much stack space the heap and stack can overlap and we can run into corruption problems
  1122. // without any "stack overflow" exceptions; making large strings static helps prevent this
  1123. //
  1124. static TCHAR OldStatus[MAX_STATUS];
  1125. PTCHAR Text;
  1126. SlGetStatusText(OldStatus);
  1127. SlClearClientArea();
  1128. SlSetCurrentAttribute(DEFDLGATT);
  1129. SlDisplayMessageBox(SL_MSG_EXIT_DIALOG);
  1130. SlSetCurrentAttribute(DEFATT);
  1131. SlFlushConsoleBuffer();
  1132. #ifdef EFI
  1133. //
  1134. // Disable EFI watchdog
  1135. //
  1136. DisableEFIWatchDog();
  1137. #endif
  1138. while(1) {
  1139. c = SlGetChar();
  1140. if(c == ASCI_CR) {
  1141. SlWriteStatusText(OldStatus);
  1142. #ifdef EFI
  1143. //
  1144. // reset EFI watchdog
  1145. //
  1146. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  1147. #endif
  1148. return;
  1149. }
  1150. if(c == SL_KEY_F3) {
  1151. Text = BlFindMessage(SL_REBOOT_PROMPT);
  1152. SlClearClientArea();
  1153. #ifdef i386
  1154. SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED);
  1155. #else
  1156. SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED_ARC);
  1157. #endif
  1158. SlWriteStatusText(Text);
  1159. SlFlushConsoleBuffer();
  1160. while(SlGetChar() != ASCI_CR);
  1161. ArcRestart();
  1162. }
  1163. }
  1164. }
  1165. VOID
  1166. SlFriendlyError(
  1167. IN ULONG uStatus,
  1168. IN PCHAR pchBadFile,
  1169. IN ULONG uLine,
  1170. IN PCHAR pchCodeFile
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. This is called when an error occurs. It puts up a
  1175. message box, displays an informative message, and allows
  1176. the user to continue. It is intended to give friendlier
  1177. messages than the SlError macro, in the cases where SlError
  1178. gets passed ARC error codes.
  1179. The status text line will be erased.
  1180. Arguments:
  1181. uStatus - ARC error code
  1182. pchBadFile - Name of file causing error (Must be given for handled
  1183. ARC codes. Optional for unhandled codes.)
  1184. uLine - Line # in source code file where error occurred (only
  1185. used for unhandled codes.)
  1186. pchCodeFile - Name of souce code file where error occurred (only
  1187. used for unhandled codes.)
  1188. Return Value:
  1189. None.
  1190. --*/
  1191. {
  1192. ULONG uMsg;
  1193. PTSTR pBadFile;
  1194. PTSTR pCodeFile;
  1195. #ifdef UNICODE
  1196. WCHAR BadFileW[64];
  1197. WCHAR CodeFileW[200];
  1198. ANSI_STRING aString;
  1199. UNICODE_STRING uString;
  1200. RtlInitString( &aString, pchBadFile );
  1201. uString.Buffer = BadFileW;
  1202. uString.MaximumLength = sizeof(BadFileW);
  1203. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  1204. RtlInitString( &aString, pchCodeFile );
  1205. uString.Buffer = CodeFileW;
  1206. uString.MaximumLength = sizeof(CodeFileW);
  1207. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  1208. if (pchBadFile) {
  1209. pBadFile = BadFileW;
  1210. } else {
  1211. pBadFile = NULL;
  1212. }
  1213. pCodeFile = CodeFileW;
  1214. #else
  1215. pBadFile = pchBadFile;
  1216. pCodeFile = pchCodeFile;
  1217. #endif
  1218. SlClearClientArea();
  1219. switch(uStatus) {
  1220. case EBADF:
  1221. case EINVAL: // image corrupt
  1222. uMsg = SL_WARNING_IMG_CORRUPT;
  1223. break;
  1224. case EIO: // i/o error
  1225. uMsg = SL_WARNING_IOERR;
  1226. break;
  1227. case ENOENT: // file not found
  1228. uMsg = SL_WARNING_NOFILE;
  1229. break;
  1230. case ENOMEM: // insufficient memory
  1231. uMsg = SL_WARNING_NOMEM;
  1232. break;
  1233. case EACCES: // unrecognized file system
  1234. uMsg = SL_WARNING_BAD_FILESYS;
  1235. break;
  1236. default: // then get SlError() behavior (with optional bad file name)
  1237. if(pBadFile) { // include error-causing file's name
  1238. SlMessageBox(
  1239. SL_WARNING_ERROR_WFILE,
  1240. pBadFile,
  1241. uStatus,
  1242. uLine,
  1243. pCodeFile
  1244. );
  1245. } else {
  1246. SlMessageBox(
  1247. SL_WARNING_ERROR,
  1248. uStatus,
  1249. uLine,
  1250. pCodeFile
  1251. );
  1252. }
  1253. return;
  1254. }
  1255. SlMessageBox(
  1256. uMsg,
  1257. pBadFile
  1258. );
  1259. }
  1260. VOID
  1261. SlMessageBox(
  1262. IN ULONG MessageId,
  1263. ...
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This is called when an error occurs. It puts up a
  1268. message box, displays an informative message, and allows
  1269. the user to continue.
  1270. The status text line will be erased.
  1271. Arguments:
  1272. MessageId - Supplies ID of message box to be presented.
  1273. any sprintf-compatible arguments to be inserted in the
  1274. message box.
  1275. Return Value:
  1276. None.
  1277. --*/
  1278. {
  1279. va_list args;
  1280. SlClearClientArea();
  1281. va_start(args, MessageId);
  1282. SlGenericMessageBox(MessageId, &args, NULL, NULL, NULL, NULL, TRUE);
  1283. va_end(args);
  1284. SlFlushConsoleBuffer();
  1285. SlGetChar();
  1286. }
  1287. ULONG
  1288. SlDisplayMessageBox(
  1289. IN ULONG MessageId,
  1290. ...
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. Just puts a message box up on the screen and returns.
  1295. The status text line will be erased.
  1296. Arguments:
  1297. MessageId - Supplies ID of message box to be presented.
  1298. any sprintf-compatible arguments to be inserted in the
  1299. message box.
  1300. Return Value:
  1301. Y position of top line of message box
  1302. --*/
  1303. {
  1304. ULONG y;
  1305. va_list args;
  1306. va_start(args, MessageId);
  1307. SlGenericMessageBox(MessageId, &args, NULL, NULL, &y, NULL, TRUE);
  1308. va_end(args);
  1309. return(y);
  1310. }
  1311. VOID
  1312. SlFatalError(
  1313. IN ULONG MessageId,
  1314. ...
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This is called when a fatal error occurs. It clears the client
  1319. area, puts up a message box, displays the fatal error message, and
  1320. allows the user to press a key to reboot.
  1321. The status text line will be erased.
  1322. Arguments:
  1323. MessageId - Supplies ID of message box to be presented.
  1324. any sprintf-compatible arguments to be inserted in the
  1325. message box.
  1326. Return Value:
  1327. Does not return.
  1328. --*/
  1329. {
  1330. va_list args;
  1331. ULONG x,y;
  1332. PTCHAR Text;
  1333. SlClearClientArea();
  1334. Text = BlFindMessage(MessageId);
  1335. if(Text) {
  1336. va_start(args, MessageId);
  1337. _vsntprintf(MessageBuffer, sizeof(MessageBuffer), Text, args);
  1338. MessageBuffer[sizeof(MessageBuffer)-1] = '\0';
  1339. //
  1340. // Add a blank line, then concatenate the 'Can't continue' text.
  1341. //
  1342. _tcscat(MessageBuffer, TEXT("\r\n"));
  1343. Text = BlFindMessage(SL_CANT_CONTINUE);
  1344. if(Text) {
  1345. _tcscat(MessageBuffer, Text);
  1346. }
  1347. Text = BlAllocateHeap(((ULONG)_tcslen(MessageBuffer)+1) * sizeof(TCHAR));
  1348. _tcscpy(Text, MessageBuffer);
  1349. //
  1350. // Note that MessageId and args won't be used, since we're
  1351. // passing in our Text pointer.
  1352. //
  1353. SlGenericMessageBox(MessageId, &args, Text, &x, NULL, &y, TRUE);
  1354. va_end(args);
  1355. } else {
  1356. SlError(MessageId);
  1357. }
  1358. SlFlushConsoleBuffer();
  1359. SlGetChar();
  1360. ArcRestart();
  1361. }
  1362. VOID
  1363. SlGenericMessageBox(
  1364. IN ULONG MessageId, OPTIONAL
  1365. IN va_list *args, OPTIONAL
  1366. IN PTCHAR Message, OPTIONAL
  1367. IN OUT PULONG xLeft, OPTIONAL
  1368. IN OUT PULONG yTop, OPTIONAL
  1369. OUT PULONG yBottom, OPTIONAL
  1370. IN BOOLEAN bCenterMsg
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. Formats and displays a message box. The longest line in the string
  1375. of characters will be centered on the screen if bCenterMsg is TRUE.
  1376. The status text line will be erased.
  1377. Arguments:
  1378. NOTE: Either the MessageId/args pair or the Message string must be
  1379. specified. Message string will be used if non-NULL.
  1380. MessageId - Supplies the MessageId that will be looked up to provide
  1381. a NULL-terminated string of characters.
  1382. Each \r\n delimited string will be displayed on its own line.
  1383. args - Supplies the argument list that will be passed to vsprintf.
  1384. Message - Supplies the actual text of the message to be displayed
  1385. xLeft - If bCenterMsg is FALSE, then xLeft is used for the starting x
  1386. coordinate of the message (if specified, otherwise, x = 1).
  1387. Also, if specified, it receives the x coordinate of the left edge
  1388. of all lines that were displayed.
  1389. yTop - If bCenterMsg is FALSE, then yTop is used for the starting y
  1390. coordinate of the message (if specified, otherwise, y = 3).
  1391. Also, if specified, receives the y coordinate of the top line where
  1392. the message box was displayed.
  1393. yBottom - if specified, receives the y coordinate of the bottom line of
  1394. the message box.
  1395. bCenterMsg - if TRUE, center message on the screen.
  1396. Return Value:
  1397. None.
  1398. --*/
  1399. {
  1400. PTCHAR p;
  1401. ULONG NumLines;
  1402. ULONG MaxLength;
  1403. ULONG x;
  1404. ULONG y;
  1405. ULONG i;
  1406. PTCHAR Line[20];
  1407. ULONG LineLength[20];
  1408. ULONG Count;
  1409. //
  1410. // set some default position values
  1411. //
  1412. x = 3;
  1413. y = ScreenHeight/2;
  1414. NumLines = 0;
  1415. if(!Message) { // then look up the message
  1416. p=BlFindMessage(MessageId);
  1417. if (p==NULL) {
  1418. SlError(MessageId);
  1419. } else {
  1420. _vsntprintf(MessageBuffer,sizeof(MessageBuffer),p,*args);
  1421. Message = MessageBuffer;
  1422. }
  1423. } else {
  1424. //
  1425. // Just make p non-NULL, so we'll know it's OK to continue.
  1426. //
  1427. p = Message;
  1428. }
  1429. if(p) {
  1430. SlWriteStatusText(TEXT("")); // Clear status bar
  1431. SlpSizeMessage(Message,
  1432. &NumLines,
  1433. &MaxLength,
  1434. LineLength,
  1435. Line);
  1436. if (MaxLength > ScreenWidth) {
  1437. MaxLength = ScreenWidth;
  1438. }
  1439. if(bCenterMsg) {
  1440. x = (ScreenWidth-MaxLength)/2;
  1441. y = (ScreenHeight-NumLines)/2;
  1442. } else {
  1443. if(xLeft) {
  1444. x = *xLeft;
  1445. } else {
  1446. x = 1;
  1447. }
  1448. if(yTop) {
  1449. y = *yTop;
  1450. } else {
  1451. y = 3;
  1452. }
  1453. }
  1454. }
  1455. for (i=0; i<NumLines; i++) {
  1456. SlPositionCursor(x, y+i);
  1457. ArcWrite(ARC_CONSOLE_OUTPUT,Line[i],LineLength[i]*sizeof(TCHAR),&Count);
  1458. }
  1459. if(xLeft) {
  1460. *xLeft = x;
  1461. }
  1462. if(yTop) {
  1463. *yTop = y;
  1464. }
  1465. if(yBottom) {
  1466. *yBottom = NumLines ? y+NumLines-1 : 0;
  1467. }
  1468. }
  1469. VOID
  1470. SlpSizeMessage(
  1471. IN PTCHAR Message,
  1472. OUT PULONG Lines,
  1473. OUT PULONG MaxLength,
  1474. OUT ULONG LineLength[],
  1475. OUT PTCHAR LineText[]
  1476. )
  1477. /*++
  1478. Routine Description:
  1479. This routine walks down a message and determines the number of
  1480. lines and the maximum line length.
  1481. Arguments:
  1482. Message - Supplies a pointer to a null-terminated message
  1483. Lines - Returns the number of lines
  1484. MaxLength - Returns the length of the longest line.
  1485. LineLength - Supplies a pointer to an array of ULONGs
  1486. Returns a filled in array containing the
  1487. length of each line.
  1488. LineText - Supplies a pointer to an array of PCHARs
  1489. Returns a filled in array containing a
  1490. pointer to the start of each line.
  1491. Return Value:
  1492. None.
  1493. --*/
  1494. {
  1495. PTCHAR p;
  1496. ULONG NumLines;
  1497. ULONG Length;
  1498. p = Message;
  1499. NumLines = 0;
  1500. *MaxLength = 0;
  1501. Length = 0;
  1502. //
  1503. // walk through the string, determining the number of lines
  1504. // and the length of the longest line.
  1505. //
  1506. LineText[0]=p;
  1507. while (*p != TEXT('\0')) {
  1508. if ((*p == TEXT('\r')) && (*(p+1) == TEXT('\n'))) {
  1509. //
  1510. // End of a line.
  1511. //
  1512. if (Length > *MaxLength) {
  1513. *MaxLength = Length;
  1514. }
  1515. LineLength[NumLines] = Length;
  1516. ++NumLines;
  1517. Length = 0;
  1518. p += 2;
  1519. LineText[NumLines] = p;
  1520. } else {
  1521. ++Length;
  1522. ++p;
  1523. if (*p == TEXT('\0')) {
  1524. //
  1525. // End of the message.
  1526. //
  1527. if (Length > *MaxLength) {
  1528. *MaxLength = Length;
  1529. }
  1530. LineLength[NumLines] = Length;
  1531. ++NumLines;
  1532. }
  1533. }
  1534. }
  1535. *Lines = NumLines;
  1536. }
  1537. VOID
  1538. SlNoMemError(
  1539. IN ULONG Line,
  1540. IN PCHAR File
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
  1545. Arguments:
  1546. Line - Line number within the file the error occurred on.
  1547. File - File name where the error occurred.
  1548. Return Value:
  1549. None.
  1550. --*/
  1551. {
  1552. SlFatalError(SL_NO_MEMORY, Line, SlCopyStringAT(File));
  1553. }
  1554. VOID
  1555. SlBadInfLineError(
  1556. IN ULONG Line,
  1557. IN PCHAR INFFile
  1558. )
  1559. /*++
  1560. Routine Description:
  1561. Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
  1562. Arguments:
  1563. Line - Line number within the inf file the error occurred on.
  1564. INFFile - Supplies a pointer to the INF filename.
  1565. Return Value:
  1566. None.
  1567. --*/
  1568. {
  1569. SlFatalError(SL_BAD_INF_LINE, Line, SlCopyStringAT(INFFile));
  1570. }
  1571. VOID
  1572. SlErrorBox(
  1573. IN ULONG MessageId,
  1574. IN ULONG Line,
  1575. IN PCHAR File
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. Stub error routine for linking with boot\lib\parseini.c. Just passes arguments thru.
  1580. Arguments:
  1581. MessageId - Id of the message to display.
  1582. Line - Line number within the file the error occurred on.
  1583. File - File name where the error occurred.
  1584. Return Value:
  1585. None.
  1586. --*/
  1587. {
  1588. PTSTR pFile;
  1589. #ifdef UNICODE
  1590. WCHAR FileW[200];
  1591. ANSI_STRING aString;
  1592. UNICODE_STRING uString;
  1593. RtlInitString( &aString, File );
  1594. uString.Buffer = FileW;
  1595. uString.MaximumLength = sizeof(FileW);
  1596. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  1597. pFile = FileW;
  1598. #else
  1599. pFile = File;
  1600. #endif
  1601. SlMessageBox(SL_WARNING_ERROR, MessageId, Line, pFile);
  1602. }