From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CLIPR.COLORADO.EDU::JWBARBOUR" 21-JUL-1989 09:56
To:	MRGATE::"ARISIA::EVERHART"
Subj:	No Subject

Message-Id:  <8907211336.AA23569@crdgw1.ge.com>
Date: 21 Jul 89 07:30:00 MDT
From: "Jim Barbour" <jwbarbour@clipr.colorado.edu>
To: "jack" <jack@wdl1.fac.ford.com>
Cc: "everhart" <everhart@arisia.decnet>, "grs" <grs@cics.wustl.edu>,
        "tjenht" <tjenht@nusdiscs.bitnet>,
        "wilsonjl" <wilsonjl%hsdp1.decnet@hqhsd.brooks.af.mil>,
        "briand" <briand@depauw.bitnet>, "buhle" <buhle@xrt.upenn.edu>

!*** BUG FIXES...
! More now acts "reasonably" if you specify either no file
! or a file which does not exist.  Before this, more would
! crash.
!
! Also, traceback is turned off in this release...
!!!!
!*** More -- a program to peruse through files.
! MORE.TPU V 1.5 -- Written by: Jim Barbour -- January 1989.
!		    Copyright (C) University of Colorado - 1989.
! 
! To compile
! $ edit/tpu/nosection/command=more.tpu
! 
! To run
! $ edit/tpu/nocommand/section=more.sec <wildcarded-file-spec>
! 
! 
procedure tpu$init_procedure 
! Procedure to do startup procedures.
!  set(traceback,on); ! off when not debugging
!  The next procedure call generates an array of  all files that match
!  the wilcarded specification.  If no wildcards are given, only one file
!  is returned in array element # 1.
!
!  Note that this should happen before the message buffer is setup because 
!  we'll get nicer error messages that way.
!
   setup_filespec_list;!If there are no files, this procedure will not return.
!  Setup key maps. This must be done at startup time because section files
!  do not save key map lists, only the keys that were defined when the file
!  is saved.
   setup_keymaps; ! Define keys.
!
!  Create temp buffer and window.  They will be deleted after the first
!  keytroke.  They are used to cover up the message window so the user 
!  won't see the "editing session is not being journaled" error message.
!
   more_temp_buffer := create_buffer("temp");
   set (SYSTEM, more_temp_buffer);
   set (no_write,more_temp_buffer);
   set (EOB_TEXT, more_temp_buffer, "");
   set(key_map_list,more_key_map_list,more_temp_buffer);
   more_temp_window := create_window(24,1,off);
   setup_system_buffers; ! Now setup message and show buffers and windows.
   set (PROMPT_AREA, 24, 1, NONE); ! Prompt area at bottom of screen.
   create_main_buffer; ! Create and map the main buffer and window.
   setup_window;!Put the first file into the main buffer and setup status line
   map(more_temp_window,more_temp_buffer); ! cover up the journal message
   position(more_temp_window); ! put cursor in message window.
   more_prefix := 1; ! Set the prefix to be 1 until changed by user.
endprocedure;

procedure setup_window
on_error ! If an error occurs while opening a file then...
	 ! NOTE: the error message will be in the message buffer.
   unmap(more_main_window); ! allow us to see the message window
   update(all); !...
   quit; ! Exit the program.
endon_error
   erase(main_buffer); ! Clear out the main buffer.
   position(main_buffer); ! Make sure the file read will go there.
! Read the current file in the list.  The list is called more_file_spec_list
! and then index is more_file_spec_pointer
   read_file(more_file_spec_list{more_file_spec_pointer});

   position(beginning_of(main_buffer)); ! Start at the beginning of the file.
   update(more_main_window);
   setup_status; ! Put file name on status line.
endprocedure;

procedure setup_status
local status_text,fname;
!  Set fname to be the name and type only of the file.
   fname:=file_parse(more_file_spec_list{more_file_spec_pointer},"","",name)+
	  file_parse(more_file_spec_list{more_file_spec_pointer},"","",type);
!  Set up the status line to be fname (expanded to 23 chars) help information
!  and the current direction.
   status_text:=fao("!23AS",fname) +
	         "<sp>=advance 1 screen   q=quit   h=help      dir: " + 
	         get_info(get_info(main_buffer,"direction"),"name");
!  Put it into the window.
   set(status_line,more_main_window,reverse,status_text);
endprocedure

procedure setup_filespec_list
!  Expand the wildcarded filespec putting the expanded names into
!  an array.  The "top" of the array is pointed to by more_file_spec_count
   more_file_spec := get_info(command_line,"file_name");! get file_spec.
   loop exitif more_file_spec <> "";
      message("type / to exit");
      more_file_spec:=read_line("_File: ");
      if more_file_spec = "/" then quit; endif;
   endloop;
!  
!  Create the array to begin at index # 1 and to INITIALLY have 20
!  elements.  NOTE that the array can dynamically grow larger then
!  20, however, the first 20 elements are much quicker to reference.
!
   more_file_spec_list := create_array(20,1);
   more_file_spec_count := 1;
!  
!  Loop through and expand the wildcards into the array.
   loop
       more_file_spec_list{more_file_spec_count}:=file_search(more_file_spec);
       exitif (more_file_spec_list{more_file_spec_count} = "");
       more_file_spec_count := more_file_spec_count + 1;
   endloop;
   more_file_spec_count := more_file_spec_count - 1;
!
!  If no files could be matched, print an error and quit;
   if more_file_spec_count = 0 then 
       message(more_file_spec+" not found.");
       quit;
   endif;
!
!  Initialize the index to 1.
   more_file_spec_pointer := 1;
endprocedure;

! Procedure to scroll through a file by <prefix> half-pages. default=1.
procedure move_by_half
local scrolled;
! Decide if we should scroll forward a backward and then do it.
   if get_info(main_buffer,"direction") = forward then
      mymessage(fao("Moving FORWARD !UL half page!%S.",more_prefix));
      update(message_window);
      scrolled := scroll(more_main_window,10*more_prefix);
      if (scrolled = 0) then
         error_message("You are at the end of the file...");
      endif;
   else
      mymessage(fao("Moving BACKWARD !UL half page!%S.",more_prefix));
      update(message_window);
      scrolled := scroll(more_main_window,-21*more_prefix);
      if (scrolled = 0) then
         error_message("You are at the beginning of the file...");
      endif;
   endif;
endprocedure;

! Procedure to scroll through a file by <prefix> pages. default=1.
procedure move_by_page
local scrolled;
! Force a repaint of the screen, this is easier to read.
   set(scrolling,more_main_window,off,0,0,0);
! Decide if we should scroll forward a backward and then do it.
   if get_info(main_buffer,"direction") = forward then
      mymessage(fao("Moving FORWARD !UL page!%S.",more_prefix));
      update(message_window);
      scrolled := scroll(more_main_window,21*more_prefix);
      if (scrolled = 0) then
         error_message("You are at the end of the file...");
      endif;
   else
      mymessage(fao("Moving BACKWARD !UL page!%S.",more_prefix));
      update(message_window);
      scrolled := scroll(more_main_window,-21*more_prefix);
      if (scrolled = 0) then
         error_message("You are at the beginning of the file...");
      endif;
   endif;
   set(scrolling,more_main_window,on,0,0,0);
endprocedure;

! Procedure toscroll through a file by <prefix> lines.  Default=1
procedure move_by_line
local scrolled;
   if get_info(main_buffer,"direction") = forward then
      scrolled := scroll(more_main_window,more_prefix);
      if (scrolled = 0) then
         error_message("You are at the beginning of the file...");
      endif;
   else
      scrolled := scroll(more_main_window,-1 * more_prefix);
      if (scrolled = 0) then
         error_message("You are at the beginning of the file...");
      endif;
   endif;
endprocedure;

! Toggle the current direction.
procedure toggle
local status_text;
! Get the current direction and switch.
   if get_info(main_buffer,"direction") = forward then
      set(reverse,main_buffer);
   else
      set(forward,main_buffer);
   endif;
!
!  Modify the status line to indicate the change.
   setup_status;
endprocedure;
! This is a TPU procedure that turns a regular expression represented by
! a string into a pattern represented by a PATTERN.

procedure translate_re_string(patstring);
local i,	      ! index into string
      l,	      ! Length of string
      pat,	      ! The pattern returned.  This is a PATTERN data type.
     pat_str,	      ! The string which represents the pattern data type.
		      ! This is for debugging only.
      unanchored,     ! Used with the *.
      do_not,	      ! A variable used to indicate whether the editor looks
		      ! for consecutive characters in or not in brackets.
      s,	      ! Pattern used with chars between brackets.
      ch;	      ! Used for peeking ahead.

! Initialize variables.
   l := length(patstring);
   i := 1;
   unanchored := -1;
   pat := "";
  pat_str := '""';

!If the first char in the string is ^ then match only at the beginning of line
   if substr(patstring,1,i) = "^" then
      pat := line_begin;
     pat_str := "line_begin ";
      i := i + 1;
   endif;

! Loop your way through the string.
   loop exitif i > l;

! If the last character is a $ then match only at the end of a line.
      if (i = l) and (substr(patstring,i,1) = "$") then
         pat := pat & line_end;
	 pat_str := pat_str + "line_end";
	 exitif 1;
      endif;

! Examine string[i].  Note that some situations require the program to
! "peek ahead" so the next time through this loop may not be string[i+1]
      case substr(patstring,i,1)
         ['\']:

! \ is the escape character, concat the character string[i+1] to the pattern.
	    i := i + 1;
	    if i > l then
	       mymessage("Invalid RegExp -- single \ last character in string.");
	       return(0);
	    endif;
	    pat := pat & substr(patstring,i,1);
	    pat_str := pat_str + '& ' + substr(patstring,i,1);

! In the pattern string, brackets indicate that the editor should match 
! only any and only one of the characters inside.  There are 2 exceptions
! to the above rule.  First, if the character after the closing bracket is an
! asterisk (*), then the editor is to match 0 or more consecutive occurences
! of any of the characters inside the brackets.  Second, if the first 
! character inside the brackets is a carot (^) then the editor is to match
! characters not in the brackets.
	 ['[']:
	    s := "";
	    i := i + 1;
	    if substr(patstring,i,1) = "^" then
	       i := i + 1;
	       do_not := true;
	    else
	       do_not := false;
	    endif;
	    loop
	       if i > l then
	          mymessage("Invalid RegExp -- No matching ].");
		  return(0);
	       endif;
	       exitif (substr(patstring,i,1) = ']');
	       s := s + substr(patstring,i,1);
	       i := i + 1;
	    endloop;
	    if s = "" then
	       mymessage("Invalid RegExp -- Nothing inside []s.");
	       return(0);
	    endif;
	    if i > l then
	       ch := ' ';
	    else
	       ch := substr(patstring,i+1,1);
	    endif;
	    if (ch = '*') then
	       if (do_not) then
	          pat := pat & (scanl(s) | "");
		  pat_str := pat_str + '& scanl('+s+') | "") ';
	       else
		  pat := pat & (spanl(s) | "");
		  pat_str := pat_str + '& (spanl('+s+') | "") ';
	       endif;
	       i := i + 1;
	    else
	       if (do_not) then
	          pat := pat & notany(s);
		  pat_str := pat_str + '& notany("'+s+'") ';
	       else
	          pat := pat & any(s);
		  pat_str := pat_str + '& any("'+s+'") ';
	       endif;
	    endif;

! A period (.) will represent any one character.  The program gathers all
! consecutive periods into one pattern function call.  Also, it peeks ahead
! to see if the character following the last period is an asterisk, then it's
! 0 or more arbitrary characters.
	 ['.']:
	    s := 1;
	    i := i + 1;
	    loop
	       exitif i > l;
	       exitif substr(patstring,i,1) <> '.';
	       s := s + 1;
	       i := i + 1;
	    endloop;
	    if substr(patstring,i,1) = "*" then
	       s := s - 1;
	       if s > 0 then
	          pat := pat & arb(s);
	          pat_str := pat_str + "& arb("+str(s)+") ";
	       endif;
	       unanchored := 1;
	       pat := pat & unanchor;
	       pat_str := pat_str + "&<unanchor>";
	    else
	       pat := pat & arb(s);
	       pat_str := pat_str + "& arb("+str(s)+") ";
	    endif;

! This is the situation for all other characters.  Look one character
! ahead to see if it is an asterisk.  If so, then search for 0 or more
! occurences of string[i].
	 [otherwise]:
	    if i < l then
	       if substr(patstring,i+1,1) = "*" then
	          pat := pat & (spanl(substr(patstring,i,1)) | "");
		  pat_str := pat_str +'& (spanl('+substr(patstring,i,1)+") | "") ";
	          i := i + 1;
	       else
	          pat := pat & substr(patstring,i,1);
	          pat_str := pat_str + '&' + substr(patstring,i,1);
	       endif;
	    else
	       pat := pat & substr(patstring,i,1);
	       pat_str := pat_str + '&' + substr(patstring,i,1);
	    endif;
      endcase;
      if unanchored = 0 then
         pat := pat & anchor;
        pat_str := pat_str + "&<anchor>";
      endif;
      unanchored := unanchored - 1;
      i := i + 1;
   endloop;
   return(pat);
endprocedure;

! Procedure to search for the <prefix>th occurrance of a wildcarded string.
! String can not cross line boundaries.  Also, highlights the found
! test.
procedure search_for_wild
local s,prefix;
   prefix := more_prefix; ! Save a copy of more_prefix for printing out errors
   more_current_search := 0; ! Cancels any current highlighting.
   position(main_buffer);
   s := read_line("?"); ! Get the string to search for.
   if s = "" then ! if <CR> is pressed, get saved search string.
      ! If ther is not previous search string, print an error and return.
      if get_info(more_search_regexp,"type") <> string then
         error_message("No previous search expression");
	 return;
      ! Otherwise, get the saved string.
      else
	 mymessage("Searching again for "+s);
      endif;
   else ! If the user typed in a string, save it.
      more_search_regexp := s;
   endif;
!  Look for thr string <prefix> times, or until it can't be found.
   if get_info(main_buffer,"direction") = reverse then
      move_horizontal(-1);
   else
      move_horizontal(1);
   endif;
   s := translate_re_string(more_search_regexp);
   loop more_current_search := search_quietly(s,
   			     get_info(main_buffer,"direction"),no_exact);
        exitif (prefix = 1) or (more_current_search = 0);
	prefix := prefix - 1;
   endloop;

   if more_current_search = 0 then ! if the string wasn't found, then print an error.
     error_message(fao("Could not find !UL occurence!%S of !AS",more_prefix,s));

   else ! Otherwise, go to the found string, and highlight it.
      more_current_search := create_range(beginning_of(more_current_search),
				  end_of(more_current_search),reverse);
      position(end_of(more_current_search));
      message('');
      update(all);
   endif;
endprocedure;

! Procedure to search for the <prefix>th occurrance of a string.
! String can not cross line boundaries.  Also, highlights the found
! test.
procedure search_for
local s,prefix;
   prefix := more_prefix; ! Save a copy of more_prefix for printing out errors
   more_current_search := 0; ! Cancels any current highlighting.
   position(main_buffer);
   s := read_line("/"); ! Get the string to search for.
   if s = "" then ! if <CR> is pressed, get saved search string.
      ! 
      ! If ther is not previous search string, print an error and return.
      if get_info(more_search_string,"type") <> string then
         error_message("No previous search string");
	 return;
      ! Otherwise, get the saved string.
      else
         s := more_search_string;
	 mymessage("Searching again for "+s);
      endif;
   else ! If the user typed in a string, save it.
      more_search_string := s;
   endif;
!  Look for thr string <prefix> times, or until it can't be found.
   if get_info(main_buffer,"direction") = reverse then
      move_horizontal(-1);
   else
      move_horizontal(1);
   endif;
   loop more_current_search := search_quietly(s,
   			     get_info(main_buffer,"direction"),no_exact);
        exitif (prefix = 1) or (more_current_search = 0);
	prefix := prefix - 1;
   endloop;

   if more_current_search = 0 then ! if the string wasn't found, then print an error.
     error_message(fao("Could not find !UL occurence!%S of !AS",more_prefix,s));

   else ! Otherwise, go to the found string, and highlight it.
      more_current_search := create_range(beginning_of(more_current_search),
				  end_of(more_current_search),reverse);
      position(end_of(more_current_search));
      message('');
   endif;
endprocedure;

! A little procedure which will continuesly scroll through a file until
! stopped by a keypress.  Normally, the TPU will attempt to execute the
! keypress.  I've gotten arround that with some trickery.  Note that there
! is some lag time between when the key is pressed and when the scrolling
! actually stops which is not related to this trickery.
! 
procedure scroll_until_stopped
local s;
   mymessage("Enter a keystroke to stop scrolling...");
   scroll(more_main_window); ! Start the scroll.
   if get_info(main_buffer,"direction") = forward then
      s := scroll(more_main_window,1);
      if s <> 0 then
         s := read_key; 
      else
         s := scroll(more_main_window,-1);
      endif;
   else
      s := scroll(more_main_window,-1);
      if s <> 0 then
         s := read_key; 
      else
         s := scroll(more_main_window,1);
      endif;
   endif;
   mymessage("");
endprocedure;

! Print a message, spawn then erase the message.
procedure pause_more
   mymessage('type LOGOUT to return to more...');
   spawn('');
   mymessage('');
endprocedure;

! Skip <prefix-1> files and enter the next one.  d=1
procedure next_file
!
! If we are going forward, then go forward in our list.
   if current_direction = forward then
! 
! Are there any more (or enough to skip) files?
      if (more_file_spec_pointer + more_prefix > more_file_spec_count) then
         error_message("No more files.");
	 return;
      endif;
      more_file_spec_pointer := more_file_spec_pointer + more_prefix;
   else
! 
! Are there any more (or enough to skip) files?
      if (more_file_spec_pointer - more_prefix < 1) then
         error_message("No more files.");
	 return;
      endif;
      more_file_spec_pointer := more_file_spec_pointer - more_prefix;
   endif;
   setup_window;
endprocedure;

! Prints help to the terminal.
procedure give_help
local dummy;
! 
! If this is the first call to help, then setup the buffer.
   if (get_info(more_help_buffer,"type") <> buffer) then
      mymessage("just a moment...");
      more_help_buffer:=create_buffer("Help Buffer");
      set(NO_WRITE,more_help_buffer);
      set(system,more_help_buffer);
      set(eob_text,more_help_buffer,"Hit any key to return to MORE...");
      more_help_window:=create_window(1,24,off);
      dummy := mark(none);
      position(more_help_buffer);
      copy_text("    <sp>   move one screenful in the current direction");
      split_line;
      copy_text("    <cr>   move one line in the current direction"); split_line;
      copy_text("     ^L    Repaint screen."); split_line;
      copy_text("     /     search in the current direction (You will be asked for a string");
      split_line;
      copy_text("           of characters to search for.) <CR> use same string.");
      split_line;
      copy_text("     ?     search in the current direction for a regular expression");
      split_line;
      copy_text("           Pressing <CR> alone says to search again.  Valid meta-chars are:"); split_line;
      copy_text("          ^ beginning of line.    $ end of line"); split_line;
      copy_text("          [...]   Match one and only one of the characters inside the []s"); split_line;
      copy_text("          [^...]  match one and only one character not inside the []s."); split_line;
      copy_text("          .        Match any one character.  .. would match 2 and so on."); split_line;
      copy_text("          \        escape character.  Voids any special meaning of next char."); split_line;
      copy_text("          *        Match 0 or more of whatever preceded it.  [...]* and .* ") ; split_line;
      copy_text("                   are all valid.");split_line;
      copy_text("     <     move to the top of the file.  ");
      copy_text(">     move to the bottom of the file"); split_line;
      copy_text("     d/D   Move 1/2 page in the current direction"); split_line;
      copy_text("     h/H   request help (this screen)"); split_line;
      copy_text("     n/N   Go to next/prev file in list."); split_line;
      copy_text("     s/S   Scroll continously until a key is pressed.");
      split_line;
      copy_text("     t/T   toggle the current direction."); split_line;
      copy_text("     q/Q   quit");split_line;
      copy_text("     z/Z   Pause MORE.");
      position(dummy);
      mymessage(" ");
   endif;
   map(more_help_window,more_help_buffer);
   update(more_help_window);
   dummy:=read_key;
   unmap(more_help_window);
endprocedure

! Set <prefix>.  ch is the number that involked this function.
procedure get_prefix(c)
local ch,prefix,here;
!
! Position ourselves in the message buffer so we can append to the same line
! this way, we can print out one number, rather then messaging ("4","40",...)
!
   here := current_window;
   position(tpu$x_message_buffer);
   copy_text("<DELETE> or <BACKSPACE> will cancel the prefix ");
   more_prefix := 0;
   ch := c;
   loop  copy_text(ch); ! Output the current digit.
	 update(message_window);
! Don't allow the prefix to go above 999.
	 if more_prefix < 1000 then
	    prefix := ascii(ch)-ascii('0');! Calculate the actual value typed.
	    more_prefix := (more_prefix * 10) + prefix; ! Figure it in.
	 else
	    error_message('');
	 endif;
	 ch := read_char; ! Get the next number or command.
	 exitif ((ch < '0') or (ch > '9')); ! If not a number, quit loop
   endloop;
   position(here);
! 
! Execute the value of the key, or ring bell if undefined.
   mymessage('');
   if (ch = ascii(127)) or (ch = ascii(8)) then prefix := 1; mymessage('');
   else
      ch := lookup_key(key_name(ch),program);
      if (ch <> 0) then execute(ch);
      else error_message(""); endif;
   endif;
   more_prefix := 1;
! We have to update windows ourselves when we execute keystrokes.
   update(all);
endprocedure;

! Procedure to output messages propprely
procedure mymessage(mes)
local here;
   if current_buffer = tpu$x_message_buffer then
      here := 0;
   else
      here := mark(none);
   endif;
   position(end_of(tpu$x_message_buffer));
   copy_text(mes);
   split_line;
   move_vertical(-1);
   update(message_window);
   position(here);
endprocedure;

! Ring bell and print message.
procedure error_message(mes)
   set(bell,all,on) ;
   message("");
   set(bell,all,off) ;
   set(bell,broadcast,on) ;
   if mes = "" then return; endif;
   mymessage(mes) ; ! Rings bell
   update(message_window);
endprocedure ;

! Procedure to create the current buffer and window.
procedure create_main_buffer
   main_buffer := create_buffer("More buffer");
   set(eob_text,main_buffer,"[end of file]");
   set(NO_WRITE,main_buffer);
   set(key_map_list,more_key_map_list,main_buffer);
! 
   more_main_window := create_window(1,23,on);
   map(more_main_window,main_buffer);
endprocedure;

! 
! When MORE is started up, it is set up so that the first key pressed
! will first call this routine and then do whatever it is suppesed to
! do.  This routine unblocks the message window and deletes the structures
! used to block it.  The window was blocked to hide the TPU message
! Editing session is not being journaled.
! 
! Code is 1 if the key that forced this procedure is undefined.
procedure setup_message_window(code)
   mymessage(''); ! Erase the bothersome message.
   unmap(more_temp_window); ! Unmap the window.
   delete(more_temp_window); ! Delete the window
   delete(more_temp_buffer); ! and buffer.
!
! Reset the prekey and undefined_key procedures to print a blank
! message or print an blank error message respectively.
   set(pre_key_procedure,more_key_map_list,"mymessage('')");
   set(post_key_procedure,more_key_map_list,"position(message_window)");
   set(undefined_key,more_key_map_list,"error_message('')");
! 
! If key is otherwise undefined, ring bell.
   update(all);
   if code = 1 then error_message(''); endif;
! If the key is defined, TPU will now execute it's procedure.
endprocedure;

!Define keys in a particular key_map and insert that keymap into a keymap list
procedure setup_keymaps;
local ch;
   more_key_map := create_key_map("more_keys");! Create the key_map.
					       ! and list.
   more_key_map_list := create_key_map_list("more key map",more_key_map);
! 
! Bind the keys 1-9 to execute get_prefix.  DO NOT define key 0.
   ch := 49;
   loop exitif ch > 57;
      define_key("get_prefix('"+ascii(ch)+"')",key_name(ascii(ch)),
		 "prefix",more_key_map);
      ch := ch + 1;
   endloop;
! Define PF2/pf3 for debugging, this should be commented out for regular use.
! define_key("unmap(more_main_window)",pf2,"DEBUG KEY",more_key_map);
! define_key("execute(read_line('Do: '))",pf3,"debug key",more_key_map);
! Define <CR>, <SP> <FF> > < / ? d/D h/H n/N q/Q s/S t/T and z/Z to work.
   define_key("move_by_line",ret_key,"move by line",more_key_map);
   define_key("move_by_page",key_name(' '),"move by page",more_key_map);
   define_key("refresh",ctrl_l_key,"Refresh screen",more_key_map);
   define_key("position(beginning_of(current_buffer))",key_name('<'),
	   "beinning of file",more_key_map);
   define_key("position(end_of(current_buffer))",key_name('>'),
	   "end of file",more_key_map);
   define_key("search_for",key_name('/'),"Search for",more_key_map);
   define_key("search_for_wild",key_name('?'),"Wild Search for",more_key_map);
   define_key("move_by_half",key_name('d'),"move by half page",more_key_map);
   define_key("move_by_half",key_name('D'),"move by half page",more_key_map);
   define_key("give_help",key_name('h'),"Give Help",more_key_map);
   define_key("give_help",key_name('H'),"Give Help",more_key_map);
   define_key("next_file",key_name('n'),"Next/Prev file",more_key_map);
   define_key("next_file",key_name('N'),"Next/Prev file",more_key_map);
   define_key("quit",key_name('q'),"quit",more_key_map);
   define_key("quit",key_name('Q'),"quit",more_key_map);
   define_key("scroll_until_stopped",key_name('s'),
  	      "scroll in current direction until key pressed",more_key_map);
   define_key("scroll_until_stopped",key_name('S'),
  	      "scroll in current direction until key pressed",more_key_map);
   define_key("toggle",key_name('t'),"Toggle direction",more_key_map);
   define_key("toggle",key_name('T'),"Toggle direction",more_key_map);
   define_key("pause_more",key_name('z'),"Spawn out of more.",more_key_map);
   define_key("pause_more",key_name('Z'),"Spawn out of more.",more_key_map);
! Setup the prekey and undefine_key procedures to call setup_message_window
   set(self_insert,more_key_map_list,off);
   set(pre_key_procedure,more_key_map_list,"setup_message_window(0)");
   set(undefined_key,more_key_map_list,"setup_message_window(1)");
endprocedure;

! Procedure to setup message and show buffers and windows.
procedure setup_system_buffers;
!SYSTEM MESSAGE BUFFER
   tpu$x_message_buffer := create_buffer ("Message Buffer");
   set (SYSTEM, tpu$x_message_buffer);
   set (no_write,tpu$x_message_buffer);
   set (EOB_TEXT, tpu$x_message_buffer, "");
   set(key_map_list,more_key_map_list,tpu$x_message_buffer);

! Make the window 2 lines from the top so if we exit abnormally the error
! won't scroll off the screen.
   message_window := create_window (3, 22, Off);
   map(message_window,tpu$x_message_buffer);

!SHOW
   show_buffer:=create_buffer("Show Buffer");
   set(NO_WRITE,Show_buffer);
   set(system,Show_buffer);
   set(eob_text,show_buffer,"");
   info_window:=create_window(1,23,on);
endprocedure;

! Used for development, puts all global variables into a file.
procedure vardump ! for debugging
   setup_system_buffers;
   set (output_file,show_buffer,"variables.tpu_dumped");
   show(variables);
   write_file(show_buffer);
endprocedure;

on_error quit; endon_error;
! Save the section and quit.
line := read_line("Section file name (DEFAULT=MORE.TPU$SECTION): ");
if (line = "") then line := "MORE.TPU$SECTION"; endif;
save(line);
! vardump;
quit;

