Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Utility Routines Manual


Previous Contents Index

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:

  1. 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.
  2. Compile the program.
  3. Link the program with an options file to create a shareable image.
  4. Define the logical name TPU$CALLUSER to point to the file containing the USER routine.
  5. Invoke DECTPU.
  6. 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:


$  CC/LIST call_user.c

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:

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

  1. 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
  2. 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.


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
4493PRO_012.HTML