/*Last Modified:  14-JUN-1989 14:02:55.80, By: FLEMING */
/*------------------------------------------------------------------------
  | TPUCALL. This program allows one to debug your tpu$calluser routines. |
  | The first thing you must do is find out the address in memory of your |
  | calluser routines. This is done with the lib$find_image_symbol. Note  |
  | the logical TPU$CALLUSER must point to the local test copy of the     |
  | calluser routines previously link/deb/noopt with this image:	  |
  |$ cc/deb/noopt  calltpu						  |
  |$ pas/deb/noopt/nostand  calluser ! or any other language		  |
  |$ link/deb  calltpu,calluser,sys$input/opt/exe=sys$disk:[]calluser	  |
  | universal=tpu$calluser						  |
  |$ define tpu$calluser  <disk:[dir]calluser>				  |
  | 									  |
  | While in debug mode step and execute the lib$find_image_symbol. Next  |
  | give the following commands:					  |
  | DEBUG> e my_address							  |
  | DEBUG> set break <numeric value of my_address>+2			  |
  | !note set scope must be in capital letters since C is case sensitive  |
  | DEBUG> set scope TPU$CALLUSER\<calluser routine>			  |
  | DEBUG> set module/all						  |
  | DEBUG> set lang <language your calluser routines are written in >     |
  | DEBUG> go								  |
  |  Calltpu now initializes and gives control of the screen over to TPU  |
  |  via the callable TPU interface. Note the section file name is defined|
  |  in the initial routine. As written it looks for it in sys$share.     |
  |  When TPU comes up, you can do anything you normally would from within|
  |  the editor, with the exception of spawns. When the call_user is      |
  |  called you will be in your calluser code. None of the functions      |
  |  or procedures in this outer level or frame will be available in the  |
  |  debug symbol table. Thus you will need to use the >step into command |
  |  to get into the routine of interest. Once in a procedure you can set |
  |  breakpoints. Upon exiting the debugger in the calluser routines,     |
  |  control returns to TPU. You can invoke calluser multiple times       |
  |  assuming you haven't trashed the stack by now. Upon exiting from TPU |
  |  control is returned to Calltpu. Nifty huh? Due credit for this       |
  |  approach is given to a certain "Judy" on the TPU support team at     |
  |  Colorado Springs.							  |
  -------------------------------------------------------------------------*/

#include    <descrip.h>
#include    <ssdef.h>
globalvalue
	tpu$m_last_time,tpu$m_delete_context,
	tpu$m_display,tpu$m_section,
	tpu$k_options,tpu$k_sectionfile,tpu$k_fileio,
	tpu$_success;
struct	vaxstring{
			int	len;
			char	*str;
		}myfile,myproc;
struct	bpv_arg	{
			int	*routine_addr;
			int	env;
		};
struct	item_list_entry{
			short int	buffer_len;
			short	int	item_code;
			int		*buffer_addr;
			int		*ret_len;
			};
	int	lib$establish();
	int	tpu$control();
	int	tpu$initialize();
	int	tpu$handler();
	int	tpu$cleanup();
	int	initial();
	int	tpu$fileio();
main()
{
	struct	bpv_arg	add_block;
	int	cleanup_options,status;
	static int	my_address;
	char	filename[64],procname[64];
	strcpy(filename,"TPU$CALLUSER");
	myfile.str = filename;
	myfile.len = strlen(filename);
	strcpy(procname,"TPU$CALLUSER");
	myproc.str = procname; /* setup string descr for TPU$CALLUSER image*/
	myproc.len = strlen(procname);
	status = lib$find_image_symbol(&myfile,&myproc,&my_address,0);
	/* ex my_address   ;  set a break to value+2  */
	lib$establish(tpu$handler);
	add_block.routine_addr = initial; /* tell it where to find TPUsection*/
	add_block.env = 0;
	status = tpu$initialize(&add_block);
	if (status != tpu$_success)
		sys$exit(status);
	status = tpu$execute_inifile();
	if (status != tpu$_success)
		sys$exit(status);
	status = tpu$control(); /* pass control to TPU */
	if (status != tpu$_success)
		sys$exit(status);
	cleanup_options = tpu$m_last_time|tpu$m_delete_context;
	status = tpu$cleanup(&cleanup_options); /* put your toys away */
	sys$exit(status);
}

initial()
{

	/* argument vector block */
	static struct  bpv_arg add_block =
		{tpu$fileio,0};
	static struct	item_list_entry	item_list[] = 
	{
		{4,tpu$k_fileio,0,0},
		{4,tpu$k_options,0,0},
		{4,tpu$k_sectionfile,0,0},
		{0,0,0,0}
	};
	int	options;
	char	*section_name = "SYS$LIBRARY:EVEPLUS.GBL";
	
	
	/* tell TPU to use a section file and display itself */
	options = tpu$m_display|tpu$m_section;
	item_list[0].buffer_addr = &add_block;
	item_list[2].buffer_len = strlen(section_name);
	item_list[2].buffer_addr = section_name;
	item_list[1].buffer_addr = &options;
	return item_list;
}
