Index: stage2/builtins.c
===================================================================
RCS file: /cvs/grub/stage2/builtins.c,v
retrieving revision 1.96
diff -u -r1.96 builtins.c
--- stage2/builtins.c	2000/10/25 14:35:49	1.96
+++ stage2/builtins.c	2000/10/30 12:03:28
@@ -365,19 +365,102 @@
 };
 #endif /* SUPPORT_NETBOOT */
 
+/* pause_func is used by cat_func, so we have to declare it here */
+static int pause_func(char *arg, int flags);
+
 
 /* cat */
 static int
 cat_func (char *arg, int flags)
 {
+  /* c is the character to be read consecutively from the file */
   char c;
 
+  /*
+   * line_buffer holds the last line displayed
+   * if we clear the screen, we redisplay it
+   */
+  char line_buffer[81];
+
+  /* col indicates the position in line_buffer where the next character goes to */
+  int col = 0;
+
+  /* old_row and new_row are used to detect a line change while printing to the screen */
+  int old_row = getxy() & 0xFF;
+  int new_row;
+
+  /* split the argument line into it's parts */
+  char **parts = grub_strsplit(arg);
+
+  /* ptr is a pointer used to walk through the parts to determine there number */
+  char **ptr = parts;
+
+  /* num is the number of number of parts of the argument line */
+  int num = 0;
+
+  /* flag to determine, if we should pause after each page */
+  int more = 0;
+
+  /* count the parts */
+  while (*ptr)
+  {
+    num++;
+    ptr++;
+  }
+
+  /*
+   * determine if the argument line ends with "|more" where there can be an arbitrary number
+   * of whitespaces between "|" and "more"
+   */
+  if ((num >= 2) && ! grub_strcmp (parts[num - 2], "|") && ! grub_strcmp (parts[num - 1], "more"))
+    more = 1;
+  else if (num >= 1)
+  {
+    if (! grub_strcmp (parts[num - 1], "|more"))
+      more = 1;
+    else if (grub_strstr (parts[num - 1], "|more") - parts[num - 1] == strlen (parts[num - 1]) - 5)
+    {
+      more = 1;
+      parts[num - 1][strlen (parts[num - 1]) - 5] = 0;
+    }
+  }
+
   if (! grub_open (arg))
     return 1;
 
   while (grub_read (&c, 1))
+  {
     grub_putchar (c);
 
+    if (more)
+    {
+      line_buffer[col++] = c;
+
+      new_row = getxy () & 0xFF;
+
+      if (new_row >= 23)
+      {
+        int i;
+
+        if (pause_func ("Press any key to continue, ESC to abort ...", flags))
+          break;
+
+        cls();
+
+        for (i = 0; i < col; i++)
+          grub_putchar (line_buffer[i]);
+      }
+
+      if (new_row > old_row)
+      {
+        grub_memset (line_buffer, 0, col);
+        col = 0;
+      }
+
+      old_row = new_row;
+    }
+  }
+
   grub_close ();
   return 0;
 }
@@ -387,8 +470,11 @@
   "cat",
   cat_func,
   BUILTIN_CMDLINE,
-  "cat FILE",
-  "Print the contents of the file FILE."
+  "cat FILE [| more]",
+  "Print the contents of the file FILE. If \"| more\" is specified, grub will"
+  " print the contents one page at a time and ask for a key to continue or ESC"
+  " to abort. \"|\" and \"more\" don't have to be separated from each other or"
+  " from the other arguments by whitespace."
 };
 
 
@@ -805,6 +891,9 @@
   " can be used only in the grub shell."
 };
 #endif /* GRUB_UTIL */
+char **grub_strsplit (char *str);
+void clear_arg_part_array ();
+
 
 
 #ifdef SUPPORT_NETBOOT
Index: stage2/char_io.c
===================================================================
RCS file: /cvs/grub/stage2/char_io.c,v
retrieving revision 1.39
diff -u -r1.39 char_io.c
--- stage2/char_io.c	2000/10/21 00:13:55	1.39
+++ stage2/char_io.c	2000/10/30 12:03:29
@@ -805,6 +805,9 @@
 	    }
 
 	  c = getkey ();
+char **grub_strsplit (char *str);
+void clear_arg_part_array ();
+
 	  if (c == '[')
 	    {
 	      int c1, c2;
@@ -1308,6 +1311,99 @@
 
   while (*str++)
     len++;
+
+/* grub_strsplit */
+
+/*
+ * Since we cannot use dynamic memory, we have to fix the maximum number
+ * of argument parts an argument line may contain.
+ * If an argument line contains more parts, the remaining parts are lost
+ * after splitting.
+ */
+#define MAX_ARG_PARTS 100
+
+/*
+ * array to hold the pointers to the beginnings of the parts of the
+ * arguments. A NUL pointer indicates, that there are no more parts.
+ */
+static char *arg_part_array[MAX_ARG_PARTS + 1];
+
+/*
+ * Splits an argument line into separate parts.
+ * To achieve this, we iterate through the argument line skipping all
+ * white space until we reach the first non-white space character. We
+ * add its address to the arg_part_array, then iterate further until
+ * we reach the next whitespace character (which determines the end of
+ * this argument part) and replace it with a '\0'. Thus this argument
+ * part is terminated.
+ * When there are no more argument parts, we add 0 to arg_part_array
+ * to indicate the end of the argument parts.
+ */
+char **
+grub_strsplit (char *str)
+{
+  int parts = 0;
+  int i = 0;
+  char *ptr = str;
+
+  while (*ptr) {
+    while (*ptr && grub_isspace(*ptr)) {
+      ptr++;
+    }
+    if (*ptr) {
+      parts++;
+      while (*ptr && !grub_isspace(*ptr)) {
+        ptr++;
+      }
+    }
+  }
+
+  if (parts > MAX_ARG_PARTS) {
+    parts = MAX_ARG_PARTS;
+  }
+
+  ptr = str;
+  while (*ptr) {
+    while (*ptr && grub_isspace(*ptr)) {
+      ptr++;
+    }
+    if (*ptr) {
+      arg_part_array[i++] = ptr;
+
+      if (i == parts) {
+        break;
+      }
+
+      while (*ptr && !grub_isspace(*ptr)) {
+        ptr++;
+      }
+
+      *ptr = 0;
+    }
+
+    ptr++;
+  }
+
+  while ( (i < MAX_ARG_PARTS + 1) && arg_part_array[i]) {
+    arg_part_array[i++] = 0;
+  }
+
+  return arg_part_array;
+}
+
+/*
+ * This function clears the arg_part_array. You should call
+ * this function if you split something like an argument line
+ * containing passwords ...
+ */
+void
+clear_arg_part_array ()
+{
+  int i = 0;
+  while ( (i < MAX_ARG_PARTS + 1) && arg_part_array[i]) {
+    arg_part_array[i++] = 0;
+  }
+}
 
   return len;
 }
Index: stage2/shared.h
===================================================================
RCS file: /cvs/grub/stage2/shared.h,v
retrieving revision 1.67
diff -u -r1.67 shared.h
--- stage2/shared.h	2000/10/19 21:10:42	1.67
+++ stage2/shared.h	2000/10/30 12:03:29
@@ -805,6 +805,9 @@
 int grub_strlen (const char *str);
 char *grub_strcpy (char *dest, const char *src);
 
+char **grub_strsplit (char *str);
+void clear_arg_part_array ();
+
 #ifndef GRUB_UTIL
 typedef unsigned long grub_jmp_buf[6];
 #else
