In case more than 9 entries are found in the boot menu
switch into two digit mode, so entries 10 and above can
actually be selected.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1693031
Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
---
 src/boot.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 66 insertions(+), 10 deletions(-)

diff --git a/src/boot.c b/src/boot.c
index 9f82f3ca0c3e..a4795b9cb9a2 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -465,6 +465,18 @@ get_keystroke(int msec)
 
 #define DEFAULT_BOOTMENU_WAIT 2500
 
+static int scancode_to_digit(int scan_code)
+{
+    switch (scan_code) {
+    case 1 ... 10:
+        return scan_code - 1;
+    case 11:
+        return 0;
+    default:
+        return -1;
+    }
+}
+
 // Show IPL option menu.
 void
 interactive_bootmenu(void)
@@ -495,14 +507,25 @@ interactive_bootmenu(void)
     printf("Select boot device:\n\n");
     wait_threads();
 
-    // Show menu items
+    // Count menu items
     int maxmenu = 0;
     struct bootentry_s *pos;
+    hlist_for_each_entry(pos, &BootList, node)
+        maxmenu++;
+    int twodigits = (maxmenu > 9);
+
+    // Show menu items
+    maxmenu = 0;
     hlist_for_each_entry(pos, &BootList, node) {
-        char desc[77];
+        char desc[76];
         maxmenu++;
-        printf("%d. %s\n", maxmenu
-               , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        if (twodigits) {
+            printf("%d%d. %s\n", maxmenu / 10, maxmenu % 10
+                   , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        } else {
+            printf("%d. %s\n", maxmenu
+                   , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        }
     }
     if (tpm_can_show_menu()) {
         printf("\nt. TPM Configuration\n");
@@ -513,6 +536,7 @@ interactive_bootmenu(void)
     // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
     // multiple times and immediately booting the primary boot device.
     int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
+    int digit, digit1 = -1, choice = 0;
     for (;;) {
         scan_code = get_keystroke(1000);
         if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
@@ -521,16 +545,48 @@ interactive_bootmenu(void)
             printf("\n");
             tpm_menu();
         }
-        if (scan_code >= 1 && scan_code <= maxmenu+1)
-            break;
+        if (scan_code < 0) {
+            // timeout
+            continue;
+        }
+        if (scan_code == 0x01) {
+            // ESC
+            printf("\n");
+            return;
+        }
+
+        digit = scancode_to_digit(scan_code);
+        if (digit < 0) {
+            // key isn't a digit
+            continue;
+        }
+
+        if (twodigits) {
+            if (digit1 < 0) {
+                // first digit
+                printf("%d", digit);
+                digit1 = digit;
+            } else {
+                // second digit
+                printf("%d", digit);
+                choice = digit1 * 10 + digit;
+                if (choice >= 1 && choice <= maxmenu) {
+                    printf(" - good choice, booting ...\n");
+                    break;
+                }
+                printf(" - invalid choice, try again\n");
+                digit1 = -1;
+            }
+        } else {
+            if (digit >= 1 && digit <= maxmenu) {
+                choice = digit;
+                break;
+            }
+        }
     }
     printf("\n");
-    if (scan_code == 0x01)
-        // ESC
-        return;
 
     // Find entry and make top priority.
-    int choice = scan_code - 1;
     hlist_for_each_entry(pos, &BootList, node) {
         if (! --choice)
             break;
-- 
2.18.1
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-le...@seabios.org

Reply via email to