|
HP OpenVMS Utility Routines Manual
8.5 Creating and Calling a USER Routine
This section describes the steps involved in creating an executable
image for the USER routine and how to call the routine from a C program
in the DECTPU environment. The following list describes the steps in
creating the executable image:
- Write a program in the appropriate high-level language; in the
supporting example, the language is C. The program must contain a
global routine named TPU$CALLUSER.
- Compile the program.
- Link the program with an options file to create a shareable image.
- Define the logical name TPU$CALLUSER to point to the file
containing the USER routine.
- Invoke DECTPU.
- From within a DECTPU session, call the high-level program to
perform its function by specifying the built-in procedure CALL_USER
with the appropriate parameters. The built-in procedure passes the
specified parameters to the appropriate routine.
8.5.1 The CALL_USER Code
This is an example of a USER routine written in the VAX C programming
language. The comments in the code explain the various routine
functions.
/* call_user.c */
/*
A sample of a TPU CALL_USER routine written in VAX C.
The routine is compiled and linked as a shareable image and then the
DCL logical TPU$CALLUSER is defined to point at the image.
From within TPU, when the built-in CALL_USER is called, this image
will be activated and the tpu$call_user routine will be called.
This example is for VAX C but can be updated to work with DEC C with little
effort.
*/
#include <descrip.h>
extern int lib$sget1_dd(),
vaxc$crtl_init();
globalvalue
tpu$_success;
/*
Because we know we are being called from a non-C based routine, call
the CRTL initialization routine once
*/
static int
rtl_inited = 0;
extern int tpu$calluser (
int *int_param,
struct dsc$descriptor *str_param,
struct dsc$descriptor *result_param )
/*
A sample TPU CALL_USER routine that checks access to the file specified
in the str_param descriptor.
Return (in result_param):
ACCESS - specified access is allowed
NOACCESS - specified access is not allowed
ERROR - Either invalid param or the file does not exist
PARAM_ERROR - Invalid param passed
MEMORY_ERROR - An error occured allocating memory
An example from TPU code would be:
file_access := CALL_USER (0, "SYS$LOGIN:LOGIN.COM");
!
! Only look at the return value of ACCESS,
!
IF file_access = "ACCESS"
THEN
file_exists := 1;
ELSE
file_exists := 0;
ENDIF;
See the description of the CALL_USER built-in for more information on how to
use the built-in.
*/
{
static char
*error_str = "ERROR",
*param_error_str = "PARAM_ERROR",
*memory_error_str = "MEMORY_ERROR",
*access_str = "ACCESS",
*noaccess_str = "NOACCESS";
char
*result_str_ptr;
int
result_str_length;
/*
If this is the first time in, call the VAXCRTL routine to init things
*/
if (rtl_inited == 0) {
vaxc$crtl_init();
rtl_inited = 1;
}
/*
The integer must be between 0 and 7 for the
call to the C RTL routine ACCESS
*/
if ((*int_param < 0) || (*int_param > 7)) {
result_str_length = strlen (param_error_str);
result_str_ptr = param_error_str;
}
else {
/*
If we were passed a null string,
set the param_error return value
*/
if (str_param->dsc$w_length == 0) {
result_str_length = strlen (param_error_str);
result_str_ptr = param_error_str;
}
else {
/*
Because there is NO way of knowing if the descriptor we have
been passed ends with a \0, we need to create a valid string
pass to the rtl routine "access"
*/
char
*str_ptr;
/*
Allocate memory enough for the string plus the null character
*/
str_ptr = (char *) malloc (str_param->dsc$w_length + 1);
/*
Make sure the memory allocation worked...
*/
if (str_ptr == 0) {
result_str_length = strlen (memory_error_str);
result_str_ptr = memory_error_str;
}
else {
/*
Move the bytes from the descriptor into the memory
pointed to by str_ptr, and end it with a \0
Then call the access routine, free the memory
*/
sprintf (str_ptr, "%.*s\0", str_param->dsc$w_length,
str_param->dsc$a_pointer);
if (access (str_ptr, *int_param) == 0) {
result_str_length = strlen (access_str);
result_str_ptr = access_str;
}
else {
result_str_length = strlen (noaccess_str);
result_str_ptr = noaccess_str;
}
free (str_ptr);
}
}
}
/* Setup the return descriptor */
lib$sget1_dd (&result_str_length, result_param);
/*
Copy the result bytes into the descriptor's dynamic
memory
*/
memcpy (result_param->dsc$a_pointer, result_str_ptr,
result_str_length);
return tpu$_success;
}
|
Use the following command to compile the routine with the VAX C
compiler:
8.5.2 Linking the CALL_USER Image
To link the CALL_USER image as a shareable image requires a linker
option file similar to the one that follows:
! CALL_USER.OPT
call_user.obj
UNIVERSAL=TPU$CALLUSER
SYS$LIBRARY:VAXCRTL/SHARE
|
After you create the linker option file, use the following command to
link the shareable image:
$ LINK CALL_USER/OPT/SHARE/MAP/FULL
|
This command produces a shareable image named CALL_USER.EXE.
The description of the DECTPU built-in CALL_USER states that you must
define the logical name TPU$CALLUSER to point to the image that
contains the USER procedure. Use the following command to define the
logical name:
$ DEFINE TPU$CALLUSER SYS$DISK:[]CALL_USER.EXE
|
If you move the image to another device and directory, you must
appropriately revise the pointer.
8.6 Accessing the USER Routine from DECTPU
To access the USER routine from DECTPU, your code must call the
CALL_USER built-in procedure. The CALL_USER built-in procedure
activates the shareable image pointed to by the logical name
TPU$CALLUSER and calls the USER routine within that image. The
following is an example of DECTPU code that can be used with the USER
example routine in Section 8.5.1.
! Module: CALL_USER.TPU - the access routine
!
! Constants used with the call to this procedure (or directly to the call_user
! routine).
!
CONSTANT
ACCESS_FILE_EXISTS := 0,
ACCESS_FILE_EXECUTE := 1,
ACCESS_FILE_WRITE := 2,
ACCESS_FILE_DELETE := 2,
ACCESS_FILE_READ := 4,
ACCESS_FILE_EXE_DEL := ACCESS_FILE_EXECUTE + ACCESS_FILE_DELETE,
ACCESS_FILE_EXE_WRITE := ACCESS_FILE_EXE_DEL,
ACCESS_FILE_DEL_READ := ACCESS_FILE_DELETE + ACCESS_FILE_READ,
ACCESS_FILE_DEL_WRITE := ACCESS_FILE_DEL_READ,
ACCESS_FILE_EXE_READ := ACCESS_FILE_EXECUTE + ACCESS_FILE_READ;
PROCEDURE access (val, the_file)
!
! Call the CRTL function ACCESS via the TPU CALL_USER built-in
!
! 0 = exists
! 1 = execute
! 2 = write (& delete)
! 4 = read
! (add them for combinations)
! Return Values:
! 1 = requested access is allowed
! 0 = requested access is NOT allowed
! -1 = an error occured with the built-in
! Side Effects:
! A message may end up in the message buffer if there is an error
!
LOCAL
ret_val;
! Handle the call_user errors
ON_ERROR
[TPU$_BADUSERDESC] :
MESSAGE (ERROR_TEXT);
RETURN -1;
[TPU$_NOCALLUSER] :
MESSAGE ("Could not find access call_user routine - check logicals");
RETURN -1;
[TPU$_CALLUSERFAIL] :
MESSAGE ("Something is wrong in the access call_user routine");
MESSAGE (ERROR_TEXT);
RETURN -1
[OTHERWISE] :
MESSAGE (ERROR_TEXT);
RETURN -1;
ENDON_ERROR;
ret_val := CALL_USER (val, the_file);
CASE ret_val
["ACCESS"] :
RETURN 1;
["NOACCESS"] :
RETURN 0;
[OUTRANGE] :
MESSAGE ("Error with call to access routine: " + ret_val);
ENDCASE;
RETURN -1;
ENDPROCEDURE;
|
You can extend the EVE editor using the DECTPU code described at the
beginning of this section. Copy the code to a file named CALL_USER.TPU
in the current working directory and then execute the following
commands:
GET FILE CALL_USER.TPU
EXTEND ALL
To use the DECTPU routine ACCESS from EVE, write a DECTPU procedure
EVE_EXISTS, coded as follows:
PROCEDURE eve_exists (the_file)
IF access (ACCESS_FILE_EXISTS, the_file) = 1
THEN
MESSAGE ("File " + the_file + " exists");
ELSE
MESSAGE ("No such file " + the_file );
ENDIF;
ENDPROCEDURE;
|
This enables calls from the command line such as:
Command: exists sys$login:login.com
|
This command directs that the message window indicate whether the file
SYS$LOGIN:LOGIN.COM exists.
8.7 DECTPU Routines
This section describes the individual DECTPU routines.
TPU$CLEANUP
The TPU$CLEANUP routine cleans up internal data structures, frees
memory, and restores terminals to their initial state.
This is the final routine called in each interaction with DECTPU.
Format
TPU$CLEANUP flags
RETURNS
OpenVMS usage: |
cond_value |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by value |
Longword condition value. Most utility routines return a condition
value in R0. The condition value that this routine can return is listed
under Condition Value Returned.
Argument
flags
OpenVMS usage: |
mask_longword |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Flags (or mask) defining the cleanup options. The
flags argument is the address of a longword bit mask
defining the cleanup options or the address of a 32-bit mask defining
the cleanup options. This mask is the logical OR of the flag bits you
want to set. Following are the various cleanup options:
Flag1 |
Function |
TPU$M_DELETE_JOURNAL
|
Closes and deletes the journal file if it is open.
|
TPU$M_DELETE_EXITH
|
Deletes the DECTPU exit handler.
|
TPU$M_DELETE_BUFFERS
|
Deletes all text buffers. If this is not the last time you are calling
DECTPU, then all variables referring to these data structures are
reset, as if by the built-in procedure DELETE. If a buffer is deleted,
then all ranges and markers within that buffer, and any subprocesses
using that buffer, are also deleted.
|
TPU$M_DELETE_WINDOWS
|
Deletes all windows. If this is not the last time you are calling
DECTPU, then all variables referring to these data structures are
reset, as if by the built-in procedure DELETE.
|
TPU$M_DELETE_CACHE
|
Deletes the virtual file manager's data structures and caches. If this
deletion is requested, then all buffers are also deleted. If the cache
is deleted, the initialization routine has to reinitialize the virtual
file manager the next time it is called.
|
TPU$M_PRUNE_CACHE
|
Frees up any virtual file manager caches that have no pages allocated
to buffers. This frees up any caches that may have been created during
the session but are no longer needed.
|
TPU$M_EXECUTE_FILE
|
Reexecutes the command file if TPU$EXECUTE_INIFILE is called again. You
must set this bit if you plan to specify a new file name for the
command file. This option is used in conjunction with the option bit
passed to TPU$INITIALIZE indicating the presence of the /COMMAND
qualifier.
|
TPU$M_EXECUTE_PROC
|
Looks up TPU$INIT_PROCEDURE and executes it the next time
TPU$EXECUTE_INIFILE is called.
|
TPU$M_DELETE_CONTEXT
|
Deletes the entire context of DECTPU. If this option is specified, then
all other options are implied, except for executing the initialization
file and initialization procedure.
|
TPU$M_RESET_TERMINAL
|
Resets the terminal to the state it was in upon entry to DECTPU. The
terminal mailbox and all windows are deleted. If the terminal is reset,
then it is reinitialized the next time TPU$INITIALIZE is called.
|
TPU$M_KILL_PROCESSES
|
Deletes all subprocesses created during the session.
|
TPU$M_CLOSE_SECTION
2
|
Closes the section file and releases the associated memory. All
buffers, windows, and processes are deleted. The cache is purged and
the flags are set for reexecution of the initialization file and
initialization procedure. If the section is closed and if the option
bit indicates the presence of the SECTION qualifier, then the next call
to TPU$INITIALIZE attempts a new restore operation.
|
TPU$M_DELETE_OTHERS
|
Deletes all miscellaneous preallocated data structures. Memory for
these data structures is reallocated the next time TPU$INITIALIZE is
called.
|
TPU$M_LAST_TIME
|
This bit should be set only when you are calling DECTPU for the last
time. Note that if you set this bit and then recall DECTPU, the results
are unpredictable.
|
1The prefix can be TPU$M_ or TPU$V_. TPU$M_ denotes a mask
corresponding to the specific field in which the bit is set. TPU$V_ is
a bit number.
2Using the simplified callable interface does not set
TPU$_CLOSE_SECTION. This feature allows you to make multiple calls to
TPU$TPU without requiring you to open and close the section file on
each call.
Description
The cleanup routine is the final routine called in each interaction
with DECTPU. It tells DECTPU to clean up its internal data structures
and prepare for additional invocations. You can control what is reset
by this routine by setting or clearing the flags described previously.
When you finish with DECTPU, call this routine to free the memory and
restore the characteristics of the terminal to their original settings.
If you intend to exit after calling TPU$CLEANUP, do not delete the data
structures; the operating system does this automatically. Allowing the
operating system to delete the structures improves the performance of
your program.
Notes
- When you use the simplified interface, DECTPU automatically sets
the following flags:
- TPU$V_RESET_TERMINAL
- TPU$V_DELETE_BUFFERS
- TPU$V_DELETE_JOURNAL
- TPU$V_DELETE_WINDOWS
- TPU$V_DELETE_EXITH
- TPU$V_EXECUTE_PROC
- TPU$V_EXECUTE_FILE
- TPU$V_PRUNE_CACHE
- TPU$V_KILL_PROCESSES
- If this routine does not return a success status, no other calls to
the editor should be made.
Condition Value Returned
TPU$_SUCCESS
|
Normal successful completion.
|
TPU$CLIPARSE
The TPU$CLIPARSE routine parses a command line and builds the item list
for TPU$INITIALIZE.
Format
TPU$CLIPARSE string ,fileio ,call_user
RETURNS
OpenVMS usage: |
item_list |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
This routine returns the address of an item list.
Arguments
string
OpenVMS usage: |
char_string |
type: |
character string |
access: |
read only |
mechanism: |
by descriptor |
Command line. The string argument is the address of a
descriptor of a DECTPU command.
fileio
OpenVMS usage: |
vector_longword_unsigned |
type: |
bound procedure value |
access: |
read only |
mechanism: |
by descriptor |
File I/O routine. The fileio argument is the address
of a descriptor of a file I/O routine.
call_user
OpenVMS usage: |
vector_longword_unsigned |
type: |
bound procedure value |
access: |
read only |
mechanism: |
by descriptor |
Call-user routine. The call_user argument is the
address of a descriptor of a call-user routine.
Description
This routine calls CLI$DCL_PARSE to establish a command table and a
command to parse. It then calls TPU$PARSEINFO to build an item list for
TPU$INITIALIZE.
If your application parses information that is not related to the
operation of DECTPU, make sure the application obtains and uses all
non-DECTPU parse information before the application calls TPU$CLIPARSE.
You must do this because TPU$CLIPARSE destroys all parse information
obtained and stored before TPU$CLIPARSE was called.
TPU$CLOSE_TERMINAL
The TPU$CLOSE_TERMINAL routine closes the DECTPU channel to the
terminal.
Format
TPU$CLOSE_TERMINAL
RETURNS
OpenVMS usage: |
cond_value |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by value |
Longword condition value. Most utility routines return a condition
value in R0. The condition value that this routine can return is listed
under Condition Value Returned.
Arguments
None.
Description
This routine is used with the built-in procedure CALL_USER and its
associated call-user routine to control the DECTPU access to the
terminal. When a call-user routine invokes TPU$CLOSE_TERMINAL, DECTPU
closes its channel to the terminal and the channel of the DECTPU
associated mailbox.
When the call-user routine returns control to it, DECTPU automatically
reopens a channel to the terminal and redisplays the visible windows.
A call-user routine can use TPU$CLOSE_TERMINAL at any point in the
program and as many times as necessary. If the terminal is already
closed to DECTPU when TPU$CLOSE_TERMINAL is used, the call is ignored.
Condition Value Returned
TPU$_SUCCESS
|
Normal successful completion.
|
TPU$CONTROL
The TPU$CONTROL routine is the main processing routine of the DECTPU
editor. It is responsible for reading the text and commands and
executing them. When you call this routine (after calling
TPU$INITIALIZE), control is turned over to DECTPU.
Format
TPU$CONTROL [integer]
RETURNS
OpenVMS usage: |
cond_value |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by value |
Longword condition value. Most utility routines return a condition
value in R0. Condition values that this routine can return are listed
under Condition Values Returned.
Argument
integer
OpenVMS usage: |
integer |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Prevents DECTPU from displaying the message "Editing session is
not being journaled" when the calling program gives control to
DECTPU. Specify a true (odd) integer to preserve compatibility in
future releases. If you omit the parameter, DECTPU displays the message
if journaling is not enabled.
Description
This routine controls the editing session. It is responsible for
reading the text and commands and for executing them. Windows on the
screen are updated to reflect the edits made. Your program can regain
control by interrupting DECTPU
using the TPU$SPECIFY_ASYNC_ACTION routine, together with the
TPU$TRIGGER_ASYNC_ACTION routine.
Note
Control is also returned to your program if an error occurs or when you
enter either the built-in procedure QUIT or the built-in procedure
EXIT.
|
Condition Values Returned
TPU$_EXITING
|
A result of EXIT (when the default condition handler is established).
|
TPU$_NONANSICRT
|
A result of operation termination --- results when you call DECTPU with
TPU$DISPLAYFILE set to nodisplay and you attempt to execute
screen-oriented commands.
|
TPU$_QUITTING
|
A result of QUIT (when the default condition handler is established).
|
TPU$_RECOVERFAIL
|
A recovery operation was terminated abnormally.
|
|