Document revision date: 30 March 2001

## 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:

> 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

> 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

| privacy and legal statement |
4493PRO_012.HTML