Previous | Contents | Index |
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:
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 |
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 |
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 |
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 section describes the individual DECTPU routines.
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.
TPU$CLEANUP flags
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.
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.
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.
- 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.
TPU$_SUCCESS Normal successful completion.
The TPU$CLIPARSE routine parses a command line and builds the item list for TPU$INITIALIZE.
TPU$CLIPARSE string ,fileio ,call_user
OpenVMS usage: item_list type: longword (unsigned) access: read only mechanism: by reference
This routine returns the address of an item list.
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.
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.
The TPU$CLOSE_TERMINAL routine closes the DECTPU channel to the terminal.
TPU$CLOSE_TERMINAL
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.
None.
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.
TPU$_SUCCESS Normal successful completion.
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.
TPU$CONTROL [integer]
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.
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.
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.
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 |