;;; $Header: /ct/debug/debugcmds.l,v 1.16 84/02/13 11:04:04 john Exp $
;;; $Log:	/ct/debug/debugcmds.l,v $
;;;Revision 1.16  84/02/13  11:04:04  john
;;;Who knows...
;;;
;;;Revision 1.15  84/01/26  16:04:30  susan
;;;Made any vms/unix dependencies happen at runtime.
;;;
;;;Revision 1.14  84/01/07  11:47:50  susan
;;;Removed a couple of local function definitions from the file.
;;;
;;;Revision 1.13  83/12/13  09:17:44  susan
;;;Changed ct_send to ct_csend or get/set-iv.
;;;
;;;Revision 1.12  83/11/22  17:52:30  susan
;;;control-c will pop out to VMS if there are
;;;no debugger options selected by the user
;;;
;;;Revision 1.11  83/11/10  17:23:13  susan
;;;Changed various things...added initializtion of 
;;;control_c so that it doesn't happen without
;;;a function call.  Made the string "Command: "
;;;become *db%command_string*.
;;;
;;;Revision 1.10  83/10/26  10:50:54  susan
;;;Removed argument to db%screen_refresh
;;;
;;;Revision 1.9  83/10/25  17:17:44  susan
;;;Added secret command '^&' with password 'alligator
;;;so that we can break after we've made a debugger
;;;version and turned off feature debugging.
;;;
;;;Revision 1.8  83/10/18  16:26:16  susan
;;;Repaired compile error caused by a new special
;;;'tempstring' showing up.
;;;
;;;Revision 1.7  83/10/17  01:11:23  susan
;;;Minor modifications in db%new_window_configs to remove unnecessary
;;;nilling of *current_exposed_window_list*
;;;
;;;Revision 1.6  83/10/16  20:04:48  susan
;;;attempting to fix reconfigure windows
;;;
;;;Revision 1.5  83/10/16  14:13:35  susan
;;;Parentheses is wrong place.
;;;
;;;Revision 1.4  83/10/16  14:05:46  susan
;;;Fixed unbalanced parentheses
;;;
;;;Revision 1.3  83/10/16  11:54:14  susan
;;;Took out all references to echoing.  Repaired 'find string' to
;;;search through whatever the *db%current_window* was for the
;;;string.  
;;;
;;;Revision 1.2  83/10/12  12:37:49  susan
;;;no changes
;;;
;;;Revision 1.1  83/10/09  11:13:17  susan
;;;Initial revision
;;;
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                  ;;;
;;;                          DEBUG_CMDS                              ;;;
;;; Susan Rosenbaum                               August, 1983       ;;;
;;;                                                                  ;;;
;;; Functions for handling debugger commands.                        ;;;
;;;                                                                  ;;;
;;; This file is part of a proprietary software project.  Source     ;;;
;;; code and documentation describing implementation details are     ;;;
;;; available on a confidential, non-disclosure basis only.  These   ;;;
;;; materials, including this file in particular, are trade secrets  ;;;
;;; of Computer * Thought Corporation.                               ;;;
;;;                                                                  ;;;
;;; (c) Copyright 1982 and 1983,  Computer * Thought Corporation.    ;;;
;;;     All Rights Reserved.                                         ;;;
;;;                                                                  ;;;
;;; Reference materials:                                             ;;;
;;;   Foderaro and Sklower, The FRANZ LISP Manual, September 1981.   ;;;
;;;   Weinreb and Moon, LISP MACHINE MANUAL, Symbolics, July 1981.   ;;;
;;;   Charniak et al., 1980.  Artificial Intelligence Programming.   ;;;
;;;   Miller, 1982.  The C*T Ada Tutor: Guide to the Implementation. ;;;
;;;                                                                  ;;;
;;;   The following code assumes familiarity with these materials.   ;;;
;;;                                                                  ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Ensure presence of needed files. 

(comment Assumes ct_load and some suitable file_map are present)

(eval-when (compile load eval) (ct_load 'aip))	   ;AIP macros pkg. 

(eval-when (compile load eval) (ct_load 'compat))  ;Franz/LM compat pkg.

(eval-when (compile load eval) (ct_load 'ctflav))  ;flavors

(eval-when (compile load eval) (ct_load 'dbutils))	;;debugger utils.

(eval-when (compile load eval) (ct_load 'scroll))  ;;scrolling windows

#+franz
(eval-when (compile load eval) (ct_load 'format))  ; Print formating

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compiler Declarations and Global Variables -- 

#+franz (declare (macros t))
#+franz (setq *flavor-expand-macros* t)
#+franz
;declare the functions that are only called in this file
(declare (localf db%new_window_configs))
		 

(declare (special
	   *db%testing_p*
	   *db%window_count*
	   *db%bottom_mode_line*
	   *db%current_window*
	   *db%window_list*
	   *db%debugger_p*
	   *db%part_debugger_p*
	   *db%source_files*
	   *db%command_string*
	   *db%code_window*
	   *db%current_file*
	   *db%top_mode_line*
	   *db%user_window*
	   *db%help_file*
	   *current_exposed_window_list*
	   *current_debug_windows_config*
	   *db%kill_char*
	   *integer_last*
	   *integer_first*
	   *db%debug_menu*
	   *db%debug_menu_mode_line*
	   *db%large_debug_menu*
	   *db%large_debug_menu_mode_line*
	   *db%small_debug_menu*
	   *db%small_debug_menu_mode_line*))


	;;;;;;;;;;;;;;;;    
(defun  db%expand_window ()
	;;;;;;;;;;;;;;;;
  ;;Expands the current window to its max size by looking at
  ;;*db%window_count* and seeing which window is currently 'it'
  ;;*db%code_window = 0
  ;;*db%user_window = 1
  ;;*db%output_window = 2
  (ct_if *db%testing_p*				;if testing, only expand 2 windows
	 (ct_selectq  *db%window_count*
		      (0
			(db%new_window_configs '(21 1 0)))
		      (1
			(db%new_window_configs '(1 21 0)))
		      (2
			(db%new_window_configs '(1 1 20))))
	 (ct_selectq  *db%window_count*		;if debugging, expand 3 windows
		      (0
			(db%new_window_configs '(20 1 1)))
		      (1
			(db%new_window_configs '(1 20 1)))
		      (2
			(db%new_window_configs '(1 1 20))))))

	;;;;;;;;;;;;;;;;;;
(defun  db%default_windows ()
	;;;;;;;;;;;;;;;;;;
  ;;;puts the windows back into their original configurations
  (ct_if *db%testing_p* (db%new_window_configs '(11 11 0))  ;;if testing, do just 2 windows
	 (db%new_window_configs '(12 5 5))))	;else, do all 3 windows


	;;;;;;;;;;;;;;;;;;;;
(defun  db%configure_windows ()
        ;;;;;;;;;;;;;;;;;;;;
  ;;Reconfigure the window configuration according to the value returned from
  ;;*db%wgetnumberstring.  The first value will be for *db%code_window*, the
  ;;second for *db%user_window*, and the third for *db%output_window*.  If only
  ;;1 or 2 numbers is given, the other(s) default to 0.
  (db%change_mode_line *db%bottom_mode_line*
		       "Enter number of lines for each window : ")
  (let* ((number_string (db%wgetnumberstring *db%bottom_mode_line*))
	 ;;get the numbers that were input
	 (number_values (db%get_numbers_from_string number_string 3))
	 ;;get the total number of lines input
	 (total (apply '+ number_values))
	 (new_lines nil))
    (ct_if (not (second number_values))
	   (setq number_values (append number_values (list 0))))
    (ct_if (not (third number_values))
	   (setq number_values (append  number_values (list 0))))
    ;;the total number of lines must be 22
    (ct_if (not (equal 22 total))
	   (db%user_interface_error
	     "The total number of lines must add up to exactly 22")
	   (progn
	     (loop for lines in number_values
		   ;;none of the line amounts can be negatvie
		   if (minusp lines)
		   do
		   (progn
		     (db%user_interface_error
		       "Illegal Negative Value for Window Size")
		     (return nil))
		   finally
		   (progn
		     ;;set *db%current_window* to be the first window
		     ;;(starting from the current-current one) with
		     ;;a non-zero number of lines.  Set up *db%window_count*
		     ;;accordingly
		     (loop while t
			   if
			   (zerop (car
				    (nthcdr *db%window_count*
					    number_values)))
			   do
			   (progn
			     (setq *db%window_count*
				   (#+franz mod
				    #+lispm remainder
				    (1+ *db%window_count*) 3))
			     (setq *db%current_window*
				   (car
				     (nthcdr *db%window_count*
					     *db%window_list*))
				   ))
			   else do   (return (db%new_window_configs
					       number_values)))))))))
      
	     
		    
		    
	 
    
	;;;;;;;;;;;;;;
(defun  db%next_window ()
	;;;;;;;;;;;;;;
  ;;Go to the next window in the *db%window_list* by incrementing and moding
  ;;the *db%window_count*.  Make sure to get a window that has more than
  ;;zero lines displayed
  (loop while t
	do (setq *db%window_count* (#+franz mod
				    #+lispm remainder (1+ *db%window_count*) 3))
	do (setq *db%current_window* (car (nthcdr
					    *db%window_count* *db%window_list*)))
	do (ct_if (not (zerop
			 (ct_csend db%debug_window *db%current_window* lines-displayed)))
		  (return nil))))
	;;;;;;;;;;;;;;;;;;
(defun  db%previous_window ()
	;;;;;;;;;;;;;;;;;;
  ;;Go to the previous window in the *db%window_list* by decrementing and moding
  ;;the *db%window_count*.  Make sure to get a window that has more than
  ;;zero lines displayed
  (loop while t
	do (setq *db%window_count* (#+franz mod
				    #+lispm remainder (+ 2 *db%window_count*) 3))
	do (setq *db%current_window* (car (nthcdr
					    *db%window_count* *db%window_list*)))
	do (ct_if (not (zerop
			 (ct_csend db%debug_window  *db%current_window* lines-displayed)))
		  (return nil))))
	;;;;;;;;;;;;
(defun  db%next_page ()
	;;;;;;;;;;;;
  ;;send a ':next_page message to the current window
  (ct_csend db%debug_window  *db%current_window* :next_page))


	;;;;;;;;;;;;;;;;
(defun  db%previous_page ()
	;;;;;;;;;;;;;;;;
  ;;send a ':previous_page message to the current window
  (ct_csend db%debug_window *db%current_window* :previous_page))


	;;;;;;;;;;;;;
(defun  db%first_page ()
	;;;;;;;;;;;;;
  ;;send a ':top_file message to the current window
    (ct_csend db%debug_window *db%current_window* :top_file))


	;;;;;;;;;;;;
(defun  db%last_page ()
	;;;;;;;;;;;;
  ;;send a ':bottom_file message to the current window
  (ct_csend db%debug_window *db%current_window* :bottom_file))


       ;;;;;;;
(defun db%quit()
       ;;;;;;;
  (ct_if *db%debugger_p* (db%quit_debugger)
	 (*throw 'db%quit_system nil)))


	;;;;;;;;;;;;;;
(defun  db%find_string ()
	;;;;;;;;;;;;;;
  ;;Ask the user for the desired string and send the current
  ;;window a ':search message.  If found, reposition the 
  ;;window on the requested string; otherwise, give an 
  ;;error that the string wasn't found
    (db%change_mode_line *db%bottom_mode_line*
			 "Enter string:  ")
    (let* ((input_string (db%wgetstr *db%bottom_mode_line*))
	   (current_xpos (get-iv db%debug_window *db%current_window* current_xpos))
	   (current_ypos (get-iv db%debug_window *db%current_window* current_ypos))
	   (return_pos nil))
      (setq return_pos (ct_csend db%debug_window *db%current_window* :search input_string
				current_xpos current_ypos))
      (ct_if return_pos
	     (progn
	       (set-iv db%debug_window *db%current_window* current_xpos (first return_pos))
	       (set-iv db%debug_window *db%current_window* current_ypos
			(second return_pos)))
	     (db%user_interface_error "String not found"))))
			
	;;;;;;;;;;;;;;
(defun  db%choose_file ()
	;;;;;;;;;;;;;;
  ;;Give a menu from which the user can choose the file that he wants
  ;;to see displayed.  The files available are those that were originally
  ;;input when the session was begun and are found in *db%source_files*
  (let ((file_name (db%ask_literal "Select a file: " *db%source_files*)))
    (ct_if (probef file_name)
	   (progn
	     (ct_csend db%debug_window *db%code_window* :display-file
		       file_name)
	     (db%change_file_name file_name))
	   (db%user_interface_error "File not found"))))

       ;;;;;;;;;;
(defun db%help_me ()
       ;;;;;;;;;;
  ;;Display the help file in *db%user_window*
  (ct_csend db%debug_window *db%user_window* :add-file
			  *db%help_file*))




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Auxiliary functions to help with the debug commands
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
       ;;;;;;;;
(defun db%index (tempstring char &optional (start_pos #+franz 1 #+lispm 0))
       ;;;;;;;;
  #| loop through tempstring from start_pos until 'char' is found
     and return the index ; return nil otherwise  |#
  (loop for i from start_pos to #+franz (string-length tempstring)
				#+lispm (1- (string-length tempstring))
	do (ct_if (equal char (substring tempstring i #+franz 1
					              #+lispm (1+ i)))
		  (return i))
	finally (return nil)))

       ;;;;;;;;;;;;
(defun db%non_index (tempstring char &optional (start_pos 1))
       ;;;;;;;;;;;;
  #| return the index in the string which
     is not equal to 'char'  , beginning the search at 'start_pos|#
       (loop for i from start_pos to (string-length tempstring)
	     do (ct_if (not (equal char (substring tempstring i 1)))
		       (return i))
	     finally (return nil)))

       ;;;;;;;;;;;;;;;;;;;;;;;;
(defun db%convert_string_to_number (string)
       ;;;;;;;;;;;;;;;;;;;;;;;;
  #| convert a string, possibly beginning with '+' or '-'
     to its numeric equivalent  |#
  (let ((tempnum 0)
	(tempstring string)
	(negp nil))
    (ct_if (equal (substring tempstring 1 1) "-")
	   (progn
	     (setq negp t)
	     (setq tempstring (substring tempstring 2)))
	   (ct_if (equal (substring tempstring 1 1) "+")
		  (setq tempstring (substring tempstring 2))))
    (loop for i from 1 to (string-length tempstring)
	  for num = (getcharn tempstring i)
	  with place_value = 1
	  do (setq tempnum (+ (* place_value tempnum) (- num 48)))
	  do (setq place_value (* place_value 10)))
    (ct_if negp (setq tempnum (- 0 tempnum)))
    tempnum))

       ;;;;;;;;;;;;;;;;;;;;;;;
(defun db%get_numbers_from_string (string number_of_numbers)
       ;;;;;;;;;;;;;;;;;;;;;;;
  ;;loop through 'string for up to 'number_of_numbers,
  ;;converting each string-number found to its
  ;;numeric equivalent and returning the list
  ;;of numbers that are made
  (loop for i from 1 to number_of_numbers
	with tstring = string
	with tempstring
	for start_pos = (db%non_index tstring " ")
	until (not start_pos)
	for end_pos = (db%index tstring " " start_pos)
	if end_pos 
	  do (setq tempstring (substring tstring start_pos
					 (- end_pos start_pos)))
	  else  do (setq tempstring (substring tstring start_pos))
	collect (db%convert_string_to_number  tempstring)
	if end_pos
        	do (setq tstring  (substring tstring end_pos))
		else do (setq tstring " ")))
		
       ;;;;;;;;;;;;;;;;;;
(defun db%new_window_configs (lines_list)
       ;;;;;;;;;;;;;;;;;;
  #| Reconfigure the debug windows to contain the number of lines
     found in lines_list---(first lines_list) will be the amount
     of lines for *db%code_window*, (second lines_list) will
     be the amount of lines for *db%user_window*, and
     (third lines_list) will be the number of lines for
     *db%output_window*    |#
       (clear)			       ;;clear the screen
       (refresh)
       ;;get rid of old mode lines
       (delwin *db%top_mode_line*)
       (delwin *db%bottom_mode_line*)
       ;;make new mode lines
       (setq *db%top_mode_line*
	     (newwin 1 80 (first lines_list) 0))
       (setq *db%bottom_mode_line*
	     (newwin 1 80 (+  1 (first lines_list) (second lines_list)) 0))
       (db%change_file_name  *db%current_file*)
       (setq *current_exposed_window_list* (list *db%top_mode_line*
						   *db%bottom_mode_line*))
       (db%change_mode_line  *db%bottom_mode_line* *db%command_string*)
       ;;make new curses windows for each window currently hanging
       ;;around
       (let ((temp_window_config *current_debug_windows_config*))
	 (setq *current_debug_windows_config* nil)
	    (loop for (window lines cols start_y start_x curses_win)
		  in temp_window_config
		  for new_lines in lines_list
		  with new_y = 0
		  do (delwin (get-iv db%debug_window (eval window)
				      curses-window))
		  do (set curses_win  (newwin new_lines cols new_y start_x))
		  do (set-iv db%debug_window (eval window)
			      curses-window (eval curses_win))
		  do (set-iv db%debug_window (eval window)
			      max_ypos (1- new_lines))
		  do (set-iv db%debug_window (eval window)
			      current_xpos 0)
		  do (set-iv db%debug_window (eval window)
			      current_ypos 0)
		  do (ct_csend db%debug_window (eval window)
			      :set-lines new_lines)
		  do (setq *current_debug_windows_config*
			   (append *current_debug_windows_config*
				 (list (list  window new_lines cols
				       new_y start_x curses_win))))
		  do (setq *current_exposed_window_list*
			   (append (list (eval window))
				   *current_exposed_window_list*))
		  do (setq new_y (+ new_y new_lines 1))))
       ;;finally, reposition the *db%current_window* again
       (ct_csend db%debug_window  *db%current_window*  :reposition_cursor))



	;;;;;;;;;;;;;;;;;
(defun db%init_control_c ()
	;;;;;;;;;;;;;;;;;
  ;;Initialize the function *db%kill_char*
  ;;for catching a control-c entered by the user
  (setq *db%kill_char* nil)
  (signal 2 'db%control_c))


       ;;;;;;;;;;;;
(defun db%control_c (signal)
       ;;;;;;;;;;;;
  ;;the function called to intercept a control-c 
  signal
  ;;if under the debugger, set the *db%kill_char* to 
  ;;'t so that interpreter execution will be halted the
  ;;next time around the loop
  ;;Otherwise, throw out to VMS
  (ct_if (or *db%debugger_p*
	     *db%part_debugger_p*)
	 (setq *db%kill_char* t)
	 (db%quit))
  ;;if debugging, cause a lisp break; but first,
  ;;turn off crmode and turn echo on
  (ct_if (status feature debugging)
	 (progn
	   (nocrmode)
	   (echo)
	   (break)
	   (crmode)
	   (noecho))))


       ;;;;;;;;;;;;;
(defun db%ask_cursor (&optional window)
       ;;;;;;;;;;;;;
  ;;return the (x,y) cursor position from the given window,
  ;;or from *db%current_window* if no window is supplied
  (ct_if window
	 (list (get-iv db%debug_window window current_xpos)
	       (get-iv db%debug_window window current_ypos))
	 (list (get-iv db%debug_window *db%current_window* current_xpos)
	       (get-iv db%debug_window *db%current_window* current_ypos))))

		  
       ;;;;;;;;;;;;;
(defun db%ask_string (prompt max_length &optional default)
       ;;;;;;;;;;;;;
  ;;Prompt the user to input a string of at most 'max_length
  ;;with prompt 'prompt and the default answer of 'default
  (let ((temp_string nil)
	(long_string (ct_if (eq max_length 'positive)
			 *integer_last*
			 max_length)))
    (ct_if default
	   (setq temp_string (ct_format nil "~A  [~A]:~3X"
					prompt  default))
	   (setq temp_string (ct_format nil "~A [null string]:~3X"
					prompt )))
    (loop while t
	  with input_string = nil
	  do (db%change_mode_line *db%bottom_mode_line*
				  temp_string)
	  do (setq input_string (db%wgetstr *db%bottom_mode_line*))
	  do (ct_if (equal input_string "")
		    (ct_if default (return default)
			   (return nil)))
	  when (< (string-length input_string) long_string)
	       return input_string
	       else do (db%user_interface_error "String too long"))))

       ;;;;;;;;;;;;;;
(defun db%ask_integer (prompt low high &optional default)
       ;;;;;;;;;;;;;;
  ;;Prompt the user to input an integer with prompt 'prompt,
  ;;lowest allowed value 'low, highest allowed value 'high,
  ;; and optional default value 'default
  (let ((temp_string nil)
	(low_num (ct_if (eq low 'negative)
			*integer_first*
			low))
	(high_num (ct_if (eq high 'positive)
			 *integer_last*
			 high)))
		 
    (ct_if default
	   (setq temp_string (ct_format nil "~A (~D to ~D) [~D]:~3X"
					prompt low high default))
	   (setq temp_string (ct_format nil "~A (~D to ~D) [~D]:~3X"
					prompt low high low)))
    (loop while t
	  with input_num = nil
	  do (db%change_mode_line *db%bottom_mode_line*
			 temp_string)
	  do (setq input_num (db%wgetnumberstring *db%bottom_mode_line*))
	  do (ct_if (or (eq input_num #\return)
			(eq input_num #\linefeed)
			(equal input_num ""))
		    (ct_if default (return default)
			   (return low)))
	  do (setq input_num (first (db%get_numbers_from_string input_num 1)))
	  when (and (>= input_num low_num)
		     (<= input_num high_num))
	     return input_num
	   else do (db%user_interace_error "Invalid number"))))

       ;;;;;;;;;;;;;;
(defun db%ask_literal (prompt item_list &optional default)
       ;;;;;;;;;;;;;;
  ;;ask the user to choose from a menu with 'prompt being
  ;;the prompt displayed and item_list consisting of either
  ;;an atom which will return itself as a value or
  ;;(item value) where item is displayed and value is returned
  ;;if that item is chosen.  The optional default choice is
  ;;found in 'default, which again will be either an item
  ;;or an item,value pair.
   (let* ((return_item (ct_if (atom (first item_list))
			     (first item_list)
			     (second (first item_list))))
	 (default_number 1)
	 (temp_string)
	 (temp_window_list *current_exposed_window_list*)
	 (temp_current_window *db%current_window*))
    (unwind-protect
      (progn
	(ct_if (> (length item_list) 5)
	       (progn
		 (setq *db%debug_menu* *db%large_debug_menu*)
		 (setq *db%current_window* *db%large_debug_menu*)
		 (setq *db%debug_menu_mode_line* *db%large_debug_menu_mode_line*))
	       (progn
		 (setq *db%debug_menu* *db%small_debug_menu*)
		 (setq *db%current_window* *db%small_debug_menu*)
		 (setq *db%debug_menu_mode_line* *db%small_debug_menu_mode_line*)))
	(setq *current_exposed_window_list*
	      (append  *current_exposed_window_list*
		       (list *db%debug_menu* *db%debug_menu_mode_line*)))
	(ct_csend db%debug_window *db%debug_menu* :clear)
	;;;next line is temporary
	(ct_csend db%debug_window *db%debug_menu* :display-string "" nil)
	(wstandout *db%debug_menu_mode_line*)
	(touchwin *db%debug_menu_mode_line*)
	(wrefresh *db%debug_menu_mode_line*)
	(loop for i from 1 to (length item_list)
	      for element in item_list
	      do (ct_csend db%debug_window *db%debug_menu* :add-line
			  (format nil "~3X~D:~2X~A" i
				  (ct_if (atom element)
					 element
					 (first element)) nil))
	      do (ct_if (and default
			     (equal default element))
			(setq default_number i)))
	(setq temp_string (ct_format nil "~A ~2X [~D]:~3X"
				     prompt default_number))
	(ct_csend db%debug_window *db%debug_menu* :touchwin)
	(ct_csend db%debug_window *db%debug_menu* :beginning)
	(loop while t
	      with input_num = nil
	      do (db%change_mode_line *db%debug_menu_mode_line*
				      temp_string)
	      do (setq input_num (db%wgetmenu_choices *db%debug_menu_mode_line* temp_string))
	      do (ct_if (or (eq input_num #\return)
			    (eq input_num #\linefeed)
			    (equal input_num ""))
			(progn
			  (ct_if default
				 (ct_if (atom default) (return default)
					(return (second default)))
				 (return return_item))))
	      do (setq input_num (1- (first
				       (db%get_numbers_from_string input_num 1))))
	      when (and (>= input_num 0)
			(<= input_num (1- (length item_list))))
	      do
	      (progn
		(setq return_item (car (nthcdr input_num item_list)))
		(ct_if (atom return_item)
		       (return return_item)
		       (return (second return_item))))
	      else do (db%user_interface_error "No such menu item")))
      (progn
	(wclear *db%debug_menu_mode_line*)
	(wrefresh *db%debug_menu_mode_line*)
	(setq *current_exposed_window_list*
	      temp_window_list)
	(setq *db%current_window* temp_current_window)
	(db%redisplay_after_menu *db%debug_menu*)))))

       ;;;;;;;;;;;;;;;;;;;;;;;
(defun db%ask_multiple_literal (prompt item_list &optional default)
       ;;;;;;;;;;;;;;;;;;;;;;;
  ;;ask the user to choose from a menu with 'prompt being
  ;;the prompt displayed and item_list consisting of either
  ;;an atom which will return itself as a value or
  ;;(item value) where item is displayed and value is returned
  ;;if that item is chosen.  The optional default choice is
  ;;found in 'default, which again will be either an item
  ;;or an item,value pair.
  ;;Multiple items are allowed to be chosen.
  (let* ((initial_item (first item_list))
	 (return_item_list (ct_if (atom initial_item)
				  (list initial_item)
				  (list (second initial_item))))
	 (default_number 1)
	 (temp_string nil)
	 (temp_current_window *db%current_window*)
	 (temp_window_list *current_exposed_window_list*))
    (unwind-protect
      (progn
	(ct_if (> (length item_list) 5)
	       (progn
		 (setq *db%debug_menu* *db%large_debug_menu*)
		 (setq *db%current_window* *db%large_debug_menu*)
		 (setq *db%debug_menu_mode_line* *db%large_debug_menu_mode_line*))
	       (progn
		 (setq *db%debug_menu* *db%small_debug_menu*)
		 (setq *db%current_window* *db%small_debug_menu*)
		 (setq *db%debug_menu_mode_line* *db%small_debug_menu_mode_line*)))
	(setq *current_exposed_window_list*
	      (append  *current_exposed_window_list*
		       (list *db%debug_menu* *db%debug_menu_mode_line*)))
	(ct_csend db%debug_window *db%debug_menu* :clear)
	;;;next line is temporary
	(ct_csend db%debug_window *db%debug_menu* :display-string "" nil)
	(wstandout *db%debug_menu_mode_line*)
	(touchwin *db%debug_menu_mode_line*)
	(wrefresh *db%debug_menu_mode_line*)
	(loop for i from 1 to (length item_list)
	      for element in item_list
	      do (ct_csend db%debug_window *db%debug_menu* :add-line
			  (format nil "~3X~D:~2X~A" i
				  (ct_if (atom element)
					 element
					 (first element)) nil))
	      do (ct_if (and default
			     (equal default element))
			(setq default_number i)))
	(setq temp_string (ct_format nil "~A ~2X [~D]:~3X"
				     prompt default_number))
	(ct_csend db%debug_window *db%debug_menu* :touchwin)
	(ct_csend db%debug_window  *db%debug_menu* :beginning)
	(loop while t
	      with input_num = nil
	      with input_numbers = nil
	      do (db%change_mode_line *db%debug_menu_mode_line*
				      temp_string)
	      do (setq input_num (db%wgetmenu_choices *db%debug_menu_mode_line* temp_string))
	      do (ct_if (or (eq input_num #\return)
			    (eq input_num #\linefeed)
			    (equal input_num ""))
			(progn
			  (ct_if default
				 (ct_if (atom default) (return (list default))
					(return (list (seocnd default))))
				 (return return_item_list))))
	      do (setq input_numbers  (db%get_numbers_from_string input_num
							       (length item_list)))
	      when (db%legal_input_numbers input_numbers  (length item_list))
	      do		
	      (progn
		(setq input_numbers
		      (loop for number in input_numbers
			    with new_list = nil
			    if (not (memq number new_list))
			    do (setq new_list (append new_list (list number)))
			    finally (return new_list)))
		(setq return_item_list
		      (loop for number in input_numbers
			    for return_item = (car (nthcdr (1- number)
							   item_list))
			    with return_item_value
			    do (ct_if (atom return_item)
				      (setq return_item_value return_item)
				      (setq return_item_value
					    (second return_item)))
			    collect return_item_value))
		(return return_item_list))
	      else do (db%user_interface_error  "No such menu item")))
      (progn
	(wclear *db%debug_menu_mode_line*)
	(wrefresh *db%debug_menu_mode_line*)
	(setq *current_exposed_window_list*
	      temp_window_list)
	(setq *db%current_window* temp_current_window)
	(db%redisplay_after_menu *db%debug_menu*)))))




       ;;;;;;;;;;;;;;;;;;;
(defun db%legal_input_numbers (number_list max_num)
       ;;;;;;;;;;;;;;;;;;;
  ;;Checks that each number in 'number_list is between
  ;;1 and the max_num allowed
    (loop for number in number_list
	  if (not (and
		     (>= number 1)
		     (<= number max_num)))
	      do (return nil)
	  finally (return t)))

       ;;;;;;;;;;;;;
(defun db%secret_out ()
       ;;;;;;;;;;;;;
  ;;Asks for the "secret" password so that we can still
  ;;break into a dumped version of the interpreter/debugger
  ;;that has debugging turned off
    (let ((secret_string (db%ask_string "What is the secret password? "
					'positive)))
	 (ct_if (equal secret_string "alligator")
		(break t))))
