Source code of Windows XP (NT5)
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.

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