Initial work on simple menu system; add <minmax.h> to libutil
authorhpa <hpa>
Mon, 20 Dec 2004 23:19:36 +0000 (23:19 +0000)
committerhpa <hpa>
Mon, 20 Dec 2004 23:19:36 +0000 (23:19 +0000)
com32/libutil/include/minmax.h [new file with mode: 0644]
com32/modules/menu.c [new file with mode: 0644]

diff --git a/com32/libutil/include/minmax.h b/com32/libutil/include/minmax.h
new file mode 100644 (file)
index 0000000..319db16
--- /dev/null
@@ -0,0 +1,44 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _MINMAX_H
+#define _MINMAX_H
+
+/*
+ * minmax.h: Type-independent safe min/max macros
+ */
+
+#define min(x,y) ({ __typeof(x) xx = (x); \
+                    __typeof(y) yy = (y); \
+                    xx < yy ? xx : yy; })
+#define max(x,y) ({ __typeof(x) xx = (x); \
+                    __typeof(y) yy = (y); \
+                    xx > yy ? xx : yy; })
+
+#endif /* _MINMAX_H */
+
diff --git a/com32/modules/menu.c b/com32/modules/menu.c
new file mode 100644 (file)
index 0000000..357952c
--- /dev/null
@@ -0,0 +1,240 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menu.c
+ *
+ * Simple menu system which displays a list and allows the user to select
+ * a command line and/or edit it.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <consoles.h>
+#include <getkey.h>
+#include <minmax.h>
+#ifdef __COM32__
+#include <com32.h>
+#endif
+
+struct menu_entry {
+  const char *displayname;
+  const char *cmdline;
+};
+
+struct menu_entry menu_entries[] =
+  {
+    { "Test", "vmlinux root=/dev/zero" },
+    { "this", "chain.c32 hd0 2" },
+    { "entry 3", "runentry val=3" },
+    { "entry 4", "runentry val=3" },
+    { "entry 5", "runentry val=3" },
+    { "entry 6", "runentry val=3" },
+    { "entry 7", "runentry val=3" },
+    { "entry 8", "runentry val=3" },
+    { "entry 9", "runentry val=3" },
+    { "entry 10", "runentry val=10" },
+    { "entry 11", "runentry val=11" },
+    { "entry 12", "runentry val=12" },
+    { "entry 13", "runentry val=13" },
+    { "entry 14", "runentry val=14" },
+    { "entry 15", "runentry val=15" },
+    { "entry 16", "runentry val=16" },
+    { "entry 17", "runentry val=17" },
+    { "entry 18", "runentry val=18" },
+    { "entry 19", "runentry val=19" },
+    { "entry 20", "runentry val=20" },
+  };
+
+int nentries  = sizeof menu_entries / sizeof(struct menu_entry);
+int defentry  = 0;
+int allowedit = 1;             /* Allow edits of the command line */
+
+char *menu_title = "This is the menu title";
+
+struct menu_attrib {
+  const char *border;          /* Border area */
+  const char *title;           /* Title bar */
+  const char *unsel;           /* Unselected menu item */
+  const char *sel;             /* Selected */
+  const char *tabmsg;          /* Press [Tab] message */
+  const char *cmdmark;         /* Command line marker */
+  const char *cmdline;         /* Command line */
+  const char *screen;          /* Rest of the screen */
+};
+
+const struct menu_attrib default_attrib = {
+  .border  = "\033[0;30;44m",
+  .title   = "\033[1;36;44m",
+  .unsel   = "\033[0;37;44m",
+  .sel     = "\033[0;30;47m",
+  .tabmsg  = "\033[0;31;40m",
+  .cmdmark = "\033[1;36;40m",
+  .cmdline = "\033[0;37;40m",
+  .screen  = "\033[0;37;40m",
+};
+
+const struct menu_attrib *menu_attrib = &default_attrib;
+
+#define WIDTH          80
+#define MARGIN         10
+#define MENU_ROWS      12
+#define TABMSG_ROW     18
+#define CMDLINE_ROW    20
+#define END_ROW                24
+
+char *pad_line(const char *text, int align, int width)
+{
+  static char buffer[256];
+  int n, p;
+
+  if ( width >= (int) sizeof buffer )
+    return NULL;               /* Can't do it */
+
+  n = strlen(text);
+  if ( n >= width )
+    n = width;
+
+  memset(buffer, ' ', width);
+  buffer[width] = 0;
+  p = ((width-n)*align)>>1;
+  memcpy(buffer+p, text, n);
+
+  return buffer;
+}
+
+void draw_menu(int sel, int top)
+{
+  int x, y;
+
+  printf("\033[1;%dH%s\311", MARGIN+1, menu_attrib->border);
+  for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
+    putchar('\315');
+  putchar('\273');
+
+  printf("\033[2;%dH\272%s %s %s\272",
+        MARGIN+1,
+        menu_attrib->title,
+        pad_line(menu_title, 1, WIDTH-2*MARGIN-4),
+        menu_attrib->border);
+
+  printf("\033[3;%dH\307", MARGIN+1);
+  for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
+    putchar('\304');
+  putchar('\266');
+
+  for ( y = 4 ; y < 4+MENU_ROWS ; y++ ) {
+    int i = (y-4)+top;
+    const char *txt = (i >= nentries) ? "" : menu_entries[i].displayname;
+
+    printf("\033[%d;%dH\272%s %s %s\272",
+          y, MARGIN+1,
+          (i == sel) ? menu_attrib->sel : menu_attrib->unsel,
+          pad_line(txt, 0, WIDTH-2*MARGIN-4),
+          menu_attrib->border);
+  }
+
+  printf("\033[%d;%dH\310", y, MARGIN+1);
+  for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
+    putchar('\315');
+  putchar('\274');
+
+  if ( allowedit )
+    printf("%s\033[%d;1H%s", menu_attrib->tabmsg, TABMSG_ROW,
+          pad_line("Press [Tab] to edit options", 1, WIDTH));
+
+  printf("\033[%d;1H%s> %s%s\033[%d;1H",
+        CMDLINE_ROW, menu_attrib->cmdmark,
+        menu_attrib->cmdline,
+        pad_line(menu_entries[sel].cmdline, 0, 255),
+        END_ROW);
+}
+
+const char *run_menu(void)
+{
+  int key;
+  int done = 0;
+  int entry = defentry;
+  int top = 0;
+
+  /* Start with a clear screen */
+  printf("%s\033[2J", menu_attrib->screen);
+
+  while ( !done ) {
+    if ( top < entry-MENU_ROWS+1 )
+      top = max(entry-MENU_ROWS+1, 0);
+    else if ( top > entry )
+      top = min(entry, nentries-MENU_ROWS+1);
+
+    draw_menu(entry, top);
+
+  gkey:
+    key = get_key(stdin);
+    switch ( key ) {
+    case '\r':
+      done = 1;
+      break;
+    case KEY_UP:
+      if ( entry > 0 )
+       entry--;
+      break;
+    case KEY_DOWN:
+      if ( entry < nentries-1 )
+       entry++;
+      break;
+    case '\003':               /* Ctrl-C */
+    case '\033':               /* Esc */
+      exit(1);                 /* FIX THIS... do something sane here */
+    default:
+      printf("[%04x]", key);
+      goto gkey;
+    }
+  }
+
+  printf("\033[%d;1H\033[0m", END_ROW);
+  return menu_entries[defentry].cmdline;
+}
+
+
+void __attribute__((noreturn)) execute(const char *cmdline)
+{
+#ifdef __COM32__
+  static com32sys_t ireg;
+
+  strcpy(__com32.cs_bounce, cmdline);
+  ireg.eax.w[0] = 0x0003;      /* Run command */
+  ireg.ebx.w[0] = OFFS(__com32.cs_bounce);
+  ireg.es = SEG(__com32.cs_bounce);
+  __intcall(0x22, &ireg, NULL);
+  exit(255);  /* Shouldn't return */
+#else
+  /* For testing... */
+  printf("\n>>> %s\n", cmdline);
+  exit(0);
+#endif
+}
+
+int main(void)
+{
+  const char *cmdline;
+
+  console_ansi_raw();
+
+  fputs("\033%@\033(U", stdout); /* Enable CP 437 graphics on a real console */
+
+  cmdline = run_menu();
+  execute(cmdline);
+}
+
+