VOID TextClearDisplay( VOID ) /*++ Routine Description: Clears the video display and positions the cursor at the upper left corner of the screen (0,0). Arguments: None Returns: Nothing --*/ { if(DbcsLangId) { TextGrClearDisplay(); } else { TextTmClearDisplay(); } TextSetCursorPosition(0,0); }
// // clear display // VOID TextClearDisplay() { if(DbcsLangId) TextGrClearDisplay(); else TextTmClearDisplay(); TextSetCursorPosition(0,0); }
PUCHAR TextTmCharOut( PUCHAR pc ) /*++ Routine Description: Writes a character on the display at the current position. Newlines and tabs are interpreted and acted upon. Arguments: c - pointer to character to write Returns: Pointer to next char in string --*/ { unsigned u; UCHAR c; UCHAR temp; c = *pc; switch (c) { case '\n': if(TextRow == (VIDEO_ROWS-1)) { TextTmScrollDisplay(); TextSetCursorPosition(0,TextRow); } else { TextSetCursorPosition(0,TextRow+1); } break; case '\r': // // ignore // break; case '\t': temp = ' '; u = 8 - (TextColumn % 8); while(u--) { TextTmCharOut(&temp); } TextSetCursorPosition(TextColumn+u,TextRow); break; default : *Vp++ = c; *Vp++ = TextCurrentAttribute; TextSetCursorPosition(TextColumn+1,TextRow); } return(pc+1); }
ULONG BlpPresentMenu( IN PMENU_OPTION MenuOption, IN ULONG NumberSelections, IN ULONG Default, IN LONG Timeout ) /*++ Routine Description: Displays the menu of boot options and allows the user to select one by using the arrow keys. Arguments: MenuOption - Supplies array of menu options NumberSelections - Supplies the number of entries in the MenuOption array. Default - Supplies the index of the default operating system choice. Timeout - Supplies the timeout (in seconds) before the highlighted operating system choice is booted. If this value is -1, the menu will never timeout. Return Value: ULONG - The index of the operating system choice selected. --*/ { ULONG i; ULONG Selection; ULONG StartTime; ULONG LastTime; ULONG BiasTime=0; ULONG CurrentTime; LONG SecondsLeft; ULONG EndTime; ULONG Key; ULONG MaxLength; ULONG CurrentLength; PCHAR SelectOs; PCHAR MoveHighlight; PCHAR TimeoutCountdown; PCHAR EnabledKd; PCHAR p; BOOLEAN Moved; // // Get the strings we'll need to display. // SelectOs = BlFindMessage(BL_SELECT_OS); MoveHighlight = BlFindMessage(BL_MOVE_HIGHLIGHT); TimeoutCountdown = BlFindMessage(BL_TIMEOUT_COUNTDOWN); EnabledKd = BlFindMessage(BL_ENABLED_KD_TITLE); if ((SelectOs == NULL) || (MoveHighlight == NULL) || (EnabledKd == NULL) || (TimeoutCountdown==NULL)) { return(Default); } p=strchr(TimeoutCountdown,'\r'); if (p!=NULL) { *p='\0'; } p=strchr(EnabledKd,'\r'); if (p!=NULL) { *p='\0'; } if (NumberSelections<=1) { // // No menu if there's only one choice. // return(0); } if (Timeout==0) { // // If the timeout is zero, immediately boot the default // return(Default); } // // Find the longest string in the selections, so we know how long to // make the highlight bar. // MaxLength=0; for (i=0; i<NumberSelections; i++) { CurrentLength = strlen(MenuOption[i].Title); if (MenuOption[i].EnableDebug == TRUE) { CurrentLength += strlen(EnabledKd); } if (CurrentLength > MAX_TITLE_LENGTH) { // // This title is too long to fit on one line, so we have to // truncate it. // if (MenuOption[i].EnableDebug == TRUE) { MenuOption[i].Title[MAX_TITLE_LENGTH - strlen(EnabledKd)] = '\0'; } else { MenuOption[i].Title[MAX_TITLE_LENGTH] = '\0'; } CurrentLength = MAX_TITLE_LENGTH; } if (CurrentLength > MaxLength) { MaxLength = CurrentLength; } } Selection = Default; StartTime = GET_COUNTER(); EndTime = StartTime + (Timeout * 182) / 10; BlPrint("OS Loader V4.50\n"); TextSetCurrentAttribute(0x07); Moved = TRUE; do { TextSetCursorPosition(0,2); BlPrint(SelectOs); if(Moved) { for (i=0; i<NumberSelections; i++) { TextSetCursorPosition(0,5+i); if (i==Selection) { TextFillAttribute(0x70,MaxLength+8); TextSetCurrentAttribute(0x70); } BlPrint( " %s", MenuOption[i].Title); if (MenuOption[i].EnableDebug == TRUE) { BlPrint(EnabledKd); } TextSetCurrentAttribute(0x07); } Moved = FALSE; } else { TextSetCursorPosition(0,5+NumberSelections-1); } BlPrint(MoveHighlight); if (Timeout != -1) { LastTime = CurrentTime; CurrentTime = GET_COUNTER(); // // deal with wraparound at midnight // We can't do it the easy way because there are not exactly // 18.2 * 60 * 60 * 24 tics/day. (just approximately) // if (CurrentTime < StartTime) { if (BiasTime == 0) { BiasTime = LastTime + 1; } CurrentTime += BiasTime; } BlPrint(TimeoutCountdown); SecondsLeft = ((LONG)(EndTime - CurrentTime) * 10) / 182; if (SecondsLeft < 0) { // // Note that if the user hits the PAUSE key, the counter stops // and, as a result, SecondsLeft can become < 0. // SecondsLeft = 0; } BlPrint(" %d \n",SecondsLeft); } else { BlPrint(" \n"); } // // Poll for a key stroke. Any key disables the countdown // timer. // Key = GET_KEY(); if (Key != 0) { Timeout = -1; } if ( (Key==UP_ARROW) || (Key==DOWN_ARROW) || (Key==HOME_KEY) || (Key==END_KEY) ) { Moved = TRUE; TextSetCursorPosition(0,5+Selection); TextFillAttribute(0x07,MaxLength+8); if (Key==DOWN_ARROW) { Selection = (Selection+1) % NumberSelections; } else if (Key==UP_ARROW) { Selection = (Selection == 0) ? (NumberSelections-1) : (Selection - 1); } else if (Key==HOME_KEY) { Selection = 0; } else if (Key==END_KEY) { Selection = NumberSelections-1; } } } while ( ((Key&(ULONG)0xff) != ENTER_KEY) && ((CurrentTime < EndTime) || (Timeout == -1)) ); return(Selection); }
PCHAR BlSelectKernel( IN ULONG DriveId, IN PCHAR BootFile, OUT PCHAR *LoadOptions, IN BOOLEAN UseTimeOut ) /*++ Routine Description: Parses the boot.txt file and determines the fully-qualified name of the kernel to be booted. Arguments: BootFile - Pointer to the beginning of the loaded boot.txt file Debugger - Returns the enable/disable state of the kernel debugger UseTimeOut - Supplies whether the boot menu should time out or not. Return Value: Pointer to the name of a kernel to boot. --*/ { PCHAR *MbLines; PCHAR *OsLines; PCHAR *FileLines; #if DBG PCHAR *DebugLines; ULONG DebugLineCount; #endif ULONG FileLineCount; ULONG OsLineCount; ULONG MbLineCount; PCHAR pCurrent; PCHAR Option; MENU_OPTION MenuOption[MAX_SELECTIONS+1]; ULONG NumberSystems=0; ULONG i; LONG Timeout; ULONG Selection; ULONG DefaultSelection=0; static CHAR Kernel[128]; CHAR DosName[3]; PCHAR DefaultPath="C:\\winnt\\"; PCHAR DefaultTitle="NT (default)"; PCHAR p; *LoadOptions = NULL; if (*BootFile == '\0') { // // No boot.ini file, so we boot the default. // BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath); MenuOption[0].Path = DefaultPath; MenuOption[0].Title = DefaultTitle; MenuOption[0].MaxMemory = 0; MenuOption[0].LoadOptions = NULL; MenuOption[0].Win95 = 0; NumberSystems = 1; DefaultSelection = 0; MbLineCount = 0; OsLineCount = 0; MenuOption[0].EnableDebug = FALSE; #if DBG DebugLineCount = 0; #endif } else { FileLines = BlpFileToLines(BootFile, &FileLineCount); MbLines = BlpFindSection("[boot loader]", FileLines, FileLineCount, &MbLineCount); if (MbLines==NULL) { MbLines = BlpFindSection("[flexboot]", FileLines, FileLineCount, &MbLineCount); if (MbLines==NULL) { MbLines = BlpFindSection("[multiboot]", FileLines, FileLineCount, &MbLineCount); } } OsLines = BlpFindSection("[operating systems]", FileLines, FileLineCount, &OsLineCount); if (OsLineCount == 0) { BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath); MenuOption[0].Path = DefaultPath; MenuOption[0].Title = DefaultTitle; MenuOption[0].MaxMemory = 0; MenuOption[0].LoadOptions = NULL; MenuOption[0].Win95 = 0; NumberSystems = 1; DefaultSelection = 0; } #if DBG DebugLines = BlpFindSection("[debug]", FileLines, FileLineCount, &DebugLineCount); #endif } // // Parse the [operating systems] section // for (i=0; i<OsLineCount; i++) { if (NumberSystems == MAX_SELECTIONS) { break; } pCurrent = OsLines[i]; // // Throw away any leading whitespace // pCurrent += strspn(pCurrent, " \t"); if (*pCurrent == '\0') { // // This is a blank line, so we just throw it away. // continue; } MenuOption[NumberSystems].Path = pCurrent; // // The first space or '=' character indicates the end of the // path specifier, so we need to replace it with a '\0' // while ((*pCurrent != ' ')&& (*pCurrent != '=')&& (*pCurrent != '\0')) { ++pCurrent; } *pCurrent = '\0'; // // The next character that is not space, equals, or double-quote // is the start of the title. // ++pCurrent; while ((*pCurrent == ' ') || (*pCurrent == '=') || (*pCurrent == '"')) { ++pCurrent; } if (pCurrent=='\0') { // // No title was found, so just use the path as the title. // MenuOption[NumberSystems].Title = MenuOption[NumberSystems].Path; } else { MenuOption[NumberSystems].Title = pCurrent; } // // The next character that is either a double-quote or a \0 // indicates the end of the title. // while ((*pCurrent != '\0')&& (*pCurrent != '"')) { ++pCurrent; } // // Look for a scsi(x) ordinal to use for opens on scsi ARC paths. // This spec must immediately follow the title and is not part // of the load options. // MenuOption[NumberSystems].ForcedScsiOrdinal = -1; if(p=strstr(pCurrent,"/SCSIORDINAL:")) { *pCurrent = 0; pCurrent = p + sizeof("/SCSIORDINAL:") - 1; MenuOption[NumberSystems].ForcedScsiOrdinal = atoi(pCurrent); // pCurrent is adjusted adequately for the code that follows. } // // If there is a DEBUG parameter after the description, then // we need to pass the DEBUG option to the osloader. // MenuOption[NumberSystems].MaxMemory=0; MenuOption[NumberSystems].EnableDebug = FALSE; MenuOption[NumberSystems].LoadOptions = NULL; MenuOption[NumberSystems].Win95 = 0; if (strchr(pCurrent,'/') != NULL) { *pCurrent = '\0'; pCurrent = strchr(pCurrent+1,'/'); MenuOption[NumberSystems].LoadOptions = pCurrent; _strupr(pCurrent); if (pCurrent != NULL) { if (Option = strstr(pCurrent,"/MAXMEM")) { MenuOption[NumberSystems].MaxMemory = atoi(Option+8); } if (strstr(pCurrent, "/WIN95DOS")) { MenuOption[NumberSystems].Win95 = WIN95_DOS; } else if (strstr(pCurrent, "/WIN95")) { MenuOption[NumberSystems].Win95 = DOS_WIN95; } // // As long as /nodebug is specified, this is NO debug system // If /NODEBUG is not specified, and either one of the // DEBUGPORT or BAUDRATE is specified, this is debug system. // if (strstr(pCurrent, "/NODEBUG") == NULL) { if (strstr(pCurrent, "/DEBUG") || strstr(pCurrent, "/BAUDRATE")) { if (_stricmp(MenuOption[NumberSystems].Path, "C:\\")==0) { MenuOption[NumberSystems].EnableDebug = FALSE; } else { MenuOption[NumberSystems].EnableDebug = TRUE; } } } } } else { *pCurrent = '\0'; } ++NumberSystems; } // // Set default timeout value // if (UseTimeOut) { Timeout = 0; } else { Timeout = -1; } // // Parse the [boot loader] section // for (i=0; i<MbLineCount; i++) { pCurrent = MbLines[i]; // // Throw away any leading whitespace // pCurrent += strspn(pCurrent, " \t"); if (*pCurrent == '\0') { // // This is a blank line, so we just throw it away. // continue; } // // Check for "timeout" line // if (_strnicmp(pCurrent,"timeout",7) == 0) { pCurrent = strchr(pCurrent,'='); if (pCurrent != NULL) { if (UseTimeOut) { Timeout = atoi(++pCurrent); } } } // // Check for "default" line // else if (_strnicmp(pCurrent,"default",7) == 0) { pCurrent = strchr(pCurrent,'='); if (pCurrent != NULL) { DefaultPath = ++pCurrent; DefaultPath += strspn(DefaultPath," \t"); } } } #if DBG // // Parse the [debug] section // for (i=0; i<DebugLineCount; i++) { extern ULONG ScsiDebug; pCurrent = DebugLines[i]; // // Throw away leading whitespace // pCurrent += strspn(pCurrent, " \t"); if (*pCurrent == '\0') { // // throw away blank lines // continue; } if (_strnicmp(pCurrent,"scsidebug",9) == 0) { pCurrent = strchr(pCurrent,'='); if (pCurrent != NULL) { ScsiDebug = atoi(++pCurrent); } } } #endif // // Now look for a Title entry from the [operating systems] section // that matches the default entry from the [multiboot] section. This // will give us a title. If no entry matches, we will add an entry // at the end of the list and provide a default Title. // i=0; while (_stricmp(MenuOption[i].Path,DefaultPath) != 0) { ++i; if (i==NumberSystems) { // // Create a default entry in the Title and Path arrays // MenuOption[NumberSystems].Path = DefaultPath; MenuOption[NumberSystems].Title = DefaultTitle; MenuOption[NumberSystems].EnableDebug = FALSE; MenuOption[NumberSystems].MaxMemory = 0; MenuOption[NumberSystems].LoadOptions = NULL; MenuOption[NumberSystems].Win95 = 0; ++NumberSystems; } } DefaultSelection = i; // // Display the menu of choices // TextClearDisplay(); TextSetCursorPosition(0,0); Selection = BlpPresentMenu( MenuOption, NumberSystems, DefaultSelection, Timeout); if (MenuOption[Selection].Win95) { BlpRenameWin95Files( DriveId, MenuOption[Selection].Win95 ); } if (_strnicmp(MenuOption[Selection].Path,"C:\\",3) == 0) { // // This syntax means that we are booting a root-based os // from an alternate boot sector image. // If no file name is specified, BlpRebootDos will default to // \bootsect.dos. // BlpRebootDOS(MenuOption[Selection].Path[3] ? &MenuOption[Selection].Path[2] : NULL); // // If this returns, it means that the file does not exist as a bootsector. // This allows c:\winnt35 to work as a boot path specifier as opposed to // a boot sector image filename specifier. // } if (MenuOption[Selection].Path[1]==':') { // // We need to translate the DOS name into an ARC name // DosName[0] = MenuOption[Selection].Path[0]; DosName[1] = MenuOption[Selection].Path[1]; DosName[2] = '\0'; BlpTranslateDosToArc(DosName,Kernel); strcat(Kernel,MenuOption[Selection].Path+2); } else { strcpy(Kernel,MenuOption[Selection].Path); } pCurrent = MenuOption[Selection].LoadOptions; if (pCurrent != NULL) { // // Remove '/' from LoadOptions string. // *LoadOptions = pCurrent + 1; while (*pCurrent != '\0') { if (*pCurrent == '/') { *pCurrent = ' '; } ++pCurrent; } } else { *LoadOptions = NULL; } // // Make sure there is no trailing slash // if (Kernel[strlen(Kernel)-1] == '\\') { Kernel[strlen(Kernel)-1] = '\0'; } // // If MaxMemory is not zero, adjust the memory descriptors to eliminate // memory above the boundary line // BlpTruncateMemory(MenuOption[Selection].MaxMemory); ForcedScsiOrdinal = MenuOption[Selection].ForcedScsiOrdinal; return(Kernel); }