___________________________________________________________ User Defined Functions (UDF's) for VAX Datatrieve Donald E. Stern, Jr. - Warner Lambert Co., Milford CT ___________________________________________________________ Introduction VAX Datatrieve provides a mechanism for easily extending the functionality provided in the "vanilla" product. This additional functionality comes in the form of User Defined Functions or UDF's. This article will deal with two major topics. A system for creating and maintaining UDF's will be discussed first. Following this discussion, several specific UDF's, which have been added at our site, will be presented and discussed. Creating and Maintaining UDF's User Defined Functions are linked into the Datatrieve shareable image, DTRSHR. Several functions are already linked with DTRSHR when the product is installed. These functions include FN$ABS, FN$COS, FN$DAY, FN$LOG, FN$SHOW_TIMER, and FN$TRANS_LOG to name a few. UDF's serve a wide variety of purposes. Some functions are used in value expressions while others are used to modify the execution environment of a process. The functions linked with the Datatrieve image are specified in a Macro file called DFNFND.MAR. The code in this file provides information regarding the name Datatrieve will use for this function, the name of the routine which will be linked with the image and called when the function is used, information regarding input and output arguments, etc. The VAX DATATRIEVE Guide to Programming and Customization gives a fairly thorough explanation of what the various components of this file are and how to modify this file in order to add functions. The specific routines called when the various functions are invoked can be a Run Time Library (RTL) routine, a System Service, or a user-written routine. Although extending Datatrieve by adding UDF's is a fairly straightforward procedure, many people are discouraged from doing so because of the need to deal with Macro, the linker, etc. In a Wombat Magic presentation several years ago (Spring 1984) Phil Naecker described a process by which Datatrieve itself could be used to maintain the file DTRFND.MAR. In fact, it was pointed out that the VAX Datatrieve development team uses a similar method to maintain the file which is ultimately shipped to customers. We have implemented a system to create and maintain Datatrieve UDF's based upon this concept. This system is described in the following paragraphs. UDF Database Description There is a one-to-many relationship between a function's attributes (DTR name, external name, value, query header, etc.) and its arguments. A function can have 0 to n arguments, each having its own set of attributes (datatype, order, etc.) Two domains have been created to contain the information needed to fully specify a UDF. These domains are DTR_FUNCTION_INFO and DTR_FUNCTION_INPUTS and use the following record definitions. DEFINE RECORD DTR_FUNCTION_INFO_REC USING 01 FUNCTION. 03 DTR_FUNCTION_NAME PIC X(31). 03 FUNCTION_DESCRIPTION PIC X(60). 03 EXT_FUNCTION_NAME PIC X(31). 03 OUT_ARG_TYPE PIC X(6) VALID IF (OUT_ARG_TYPE IN FUN_TYPE_TABLE). 03 OUT_ARG_DTYPE BYTE. 03 OUT_ARG_DESCRIPTION PIC X(60). 03 EDIT_STR PIC X(31) MISSING VALUE " " QUERY_HEADER IS "EDIT STRING". 03 QUERY_HDR PIC X(80) QUERY_NAME HDR MISSING VALUE " " QUERY_HEADER IS "QUERY HEADER". 03 NOVALUE PIC X VALID IF NOVALUE EQ "Y","N" MISSING VALUE "N". 03 NO_OPTIMIZE PIC X VALID IF NOVALUE EQ "Y","N" MISSING VALUE "N". 03 IN_COUNT BYTE. ; DEFINE RECORD DTR_FUNCTION_INPUTS_REC USING 01 INPUTS. 03 DTR_FUNCTION_NAME PIC X(31). 03 IN_ARG_TYPE PIC X(5) VALID IF (IN_ARG_TYPE IN FUN_TYPE_TABLE). 03 IN_ARG_DESCRIPTION PIC X(60). 03 IN_ARG_DTYPE BYTE. 03 ORDER BYTE. 03 OUT_PUT PIC X VALID IF OUT_PUT EQ "Y","N" MISSING VALUE "N". 03 ALL_LEN WORD. ; The fields used in these records are described in the following table. Field Name Description Domain: DTR_FUNCTION_INFO DTR_FUNCTION_NAME The name of the UDF. This is the name that is used to reference the UDF from Datatrieve. FUNCTION_DESCRIPTION This is a brief description of the functions intent. The information is used to comment the MACRO code which is generated. EXT_FUNCTION_NAME This is the name of the external function which will be called when the UDF is used. OUT_ARG_TYPE This describes the value of the function. It can be a value (eg. FN$LOG10(x)) or it can return a status. OUT_ARG_DTYPE This is a code which specifies the datatype of the function. A database of valid codes and corresponding datatypes is maintained. (See Appendix IV for a listing of the domain, record, and table definitions, as well as, a listing of the valid datatypes.) OUT_ARG_DESCRIPTION This describes the output and is used to comment the generated MACRO code. EDIT_STR If a special edit-string is required, X(8) for example, this field is used to specify it. It is not required information and can be left blank. QUERY_HDR If a query header, other than the UDF name, is required then this field is used to specify it. NOVALUE This field can contain a "Y" or an "N". A "Y" indicates that no value is returned from the external function. The UDFs FN$WIDTH and FN$CREATE_LOG are examples of such functions. NO_OPTIMIZE This field can contain a "Y" or an "N". If a "Y" is stored, then the UDF will not be optimized out of a loop. The default value is "N". IN_COUNT This specifies the number of arguments to be passed to/from the external function. It corresponds exactly to the number of "member" records in DTR_FUNCTION_INPUTS. Domain: DTR_FUNCTION_INPUTS DTR_FUNCTION_NAME The DTR function name. It relates records in this domain to records in DTR_FUNCTION_INFO. IN_ARG_TYPE This field describes how the argument is passed, eg. by reference, by description, etc. IN_ARG_DESCRIPTION This describes the argument. The description is used to comment the generated MACRO code. IN_ARG_DTYPE This describes the datatype of the argument. ORDER This describes the order in which the argument appears in the argument list. OUT_PUT Permitted values are "Y" and "N". A "Y" indicates that this is a value returned from the external function rather than one passed to it. ALL_LEN If the output is of predetermined length, it is specified here. See FN$HEX and WL$OCTAL for examples. Every UDF has one, and only one, record occurrence in the domain DTR_FUNCTION_INFO. Each UDF must be identified by a unique function name, ie. FN$LOG10, this name is stored in the field DTR_FUNCTION_NAME. Records in the domain DTR_FUNCTION_INPUTS contain information about a functions arguments. The field DTR_FUNCTION_NAME is used to relate records in this domain with the corresponding "owner" record in the DTR_FUNCTION_INFO domain. Using the view definition given below the two domains are logically combined. Each record occurrence of this view contains sufficient information to completely define a UDF. DEFINE DOMAIN DTR_FUNCTIONS OF DTR_FUNCTION_INFO, DTR_FUNCTION_INPUTS USING 01 DTR_FUNCTION OCCURS FOR DTR_FUNCTION_INFO. 03 FUNCTION FROM DTR_FUNCTION_INFO. 03 IN_ARGS OCCURS FOR DTR_FUNCTION_INPUTS WITH DTR_FUNCTION_NAME = DTR_FUNCTION_INFO.DTR_FUNCTION_NAME. 05 INPUTS FROM DTR_FUNCTION_INPUTS. ; As previously pointed out, UDF's reference external functions which are called and to/from which arguments are passed. In the case of the User Defined Function FN$LOG10 the external function is the RTL routine MTH$ALOG10. The following shows the data stored for the Digital-supplied UDF FN$LOG10. DTR_FUNCTION_NAME : FN$LOG10 FUNCTION_DESCRIPTION : Common logarithm EXT_FUNCTION_NAME : MTH$ALOG10 OUT_ARG_TYPE : VALUE OUT_ARG_DTYPE : 10 OUT_ARG_DESCRIPTION : output is a floating value in R0, R1 EDIT_STR : QUERY_HDR : NOVALUE : N NO_OPTIMIZE : N IN_COUNT : 1 DTR_FUNCTION_NAME : FN$LOG10 IN_ARG_TYPE : REF IN_ARG_DESCRIPTION : input is a floating value passed by reference IN_ARG_DTYPE : 10 ORDER : 1 OUT_PUT : N ALL_LEN : 0 The data shows us that the function FN$LOG10 uses the RTL function MTH$ALOG10; that the function returns a value which is a real number; no special EDIT_STRING or QUERY_HEADER are used; that the function can be optimized out of a loop (at Datatrieve compile time); and that the function requires a single argument, a real number passed by reference. Maintaining the UDF Database The procedures ADD_DTR_FUNCTION and ADD_DTR_FUNCTIONS were created in order to add data to the database. The code for each is given in Appendix I. Separate forms were created to capture the data for DTR_FUNCTION_INFO and DTR_FUNCTION_INPUTS. While simplifying the data entry procedures, the existence of forms are not necessary; the procedures can be modified if the target system does not have FMS or TDMS installed. Two procedures, MAKE_DTRFND and PRINT_FUNCTION, are used to recreate the macro source file DTRFND.MAR. The source code is assembled and linked into the Datatrieve shareable image. The code for these procedures is given in Appendix II. MAKE_DTRFND, prints the Macro header information, executes PRINT_FUNCTION once for every record in DTR_FUNCTIONS, and prints the trailer information. PRINT_FUNCTION simply prints a DTR_FUNCTIONS record in the required format. Appendix II also contains the procedure MAKE_COMMAND which produces a DCL command file which, when executed, assembles DTRFND, copies the source, listing, and object files into a central location, and updates the library DTRFUN.OLB. Since DTRFND.MAR is completely recreated by the use of these procedures, it is necessary to load data for Digital-supplied UDF's into the database as well as any site-specific UDF's. Site Specific UDF's Naming Convention We have developed a standard set of UDF's which are linked with the shareable Datatrieve images on each of the nodes in our network. Almost without exception, UDF's previously described by users, in this and other publications, have followed the Digital naming convention. FN$name We have found it more convenient to name our UDF's using a different convention. All of our site specific UDF's are named using WL$name as the convention. By doing this, we can easily identify and separate Warner Lambert functions from those supplied by Digital. Additionally, we are able to avoid naming conflicts as new versions of Datatrieve (with new functions) are released. This significantly reduces the maintenance effort needed when re-installing Datatrieve. The following is a list of some of the UDF's which have been implemented at our site. Function Name Function Description WL$CHAR Convert an ASCII Code to an ASCII Character WL$DAY Returns the number of days since the base date 17-Nov-1858 WL$DAY_OF_WEEK Returns a numeric day of the week for a date/time WL$DELETE_FILE Delete a file WL$DELETE_LOGICAL Deletes a supervisor-mode logical from a specified table WL$EDT Edit an ASCII file WL$GET_SYMBOL Returns the value of a CLI symbol as a string WL$OCTAL Convert an unsigned integer longword to an octal char. strg. WL$POWER Computes the value of a number raised to a power WL$RANDOM A random number generator WL$RENAME_FILE Renames a file WL$SET_LOGICAL (Re)defines a supervisor mode logical in a specified table WL$SET_SYMBOL Define or redefine a CLI symbol WL$WAIT Places current process in hibernation for specified time WL$CHAR We use this function primarily to generate non-printing ASCII characters, such as BELL (ASCII code 7) and ESCAPE (ASCII code 27), which tend to disrupt the printing of procedures when the character itself is embedded in the code. In the Fall 1986 Wombat Magic session held in San Francisco, Pat Scopelletti demonstrated how the escape character could be programmed into a procedure using this function (Pat named his UDF FN$CHAR). DECLARE ESC COMPUTED BY FN$CHAR(27). : : PRINT ESC|"[?5i" !Printer on : : PRINT ESC|"[?4i" !Printer off WL$DAY_OF_WEEK This function has a single argument, a DATE variable, and returns a value between 1 and 7 (Monday = 1 and Sunday = 7). For example: DTR> PRINT "TODAY" USING WWWWWWWWW, - CON> "TODAY" USING DD-MMM-YYYY, WL$DAY_OF_WEEK("TODAY") WL$DAY OF WEEK Sunday 8-Feb-1987 7 WL$DELETE_FILE This function has a single argument, a TEXT variable, which contains a valid file specification. Unlike the DCL DELETE command, the file specification provided to this function does not require version number information. For example: DTR> WL$DELETE_FILE("YACHTS.DAT") will delete the latest version of YACHTS.DAT. This function is very useful in procedures which contain a DEFINE FILE command. The UDF can be used to clear out any older versions of the file and thereby save disk space and the need to do this housekeeping outside of Datatrieve. WL$DELETE_LOGICAL / WL$SET_LOGICAL The Digital UDF FN$CREATE_LOG is used to create User Mode logical names. These functions are used to delete/create logical names in any specified logical name table (to which the user has write access of course.) We found this particularly useful when spawning a subprocess from Datatrieve. User mode logical names will not be defined for the subprocess but Process Mode logical names will. For example, the statement DTR> WL$SET_LOGICAL("DTR$LOGICAL","My logical name", "LNM$PROCESS_TABLE") will create a logical name called DTR$LOGICAL in the process logical name table and assign the value "My logical name" to it. Similarly, the statement DTR> WL$DELETE_LOGICAL("DTR$LOGICAL","LNM$PROCESS_TABLE") will delete the logical name from the table. WL$EDT This UDF requires a single argument, a TEXT variable containing a valid file specification. It uses callable EDT to create/edit an ASCII text file. In order to incorporate this function into the Datatrieve shareable image, we had to add a reference to the EDTSHR shareable image in the link command for DTRSHR. cluster=edtrtl,,,sys$common:[syslib]edtshr.exe/shareable This UDF can be used in Datatrieve procedures to create and maintain ASCII files. In this implementation, only one argument is used however the RTL function which is referenced will take a number of optional arguments as well (an EDT initialization file, for example). The UDF could be restructured to accommodate these optional arguments as well. One could achieve the same end result using an expression such as DTR> FN$DCL("EDIT/EDT filespec") but would incur the overhead involved with spawning a subprocess and activating the EDT.EXE image. Using this function DTR> WL$EDT(filespec) will result in much less overhead and faster response time. WL$GET_SYMBOL / WL$SET_SYMBOL This pair of functions permit one to translate or define a symbol in the symbol table. This can be particularly useful if Datatrieve is executing inside of a command or batch procedure. WL$OCTAL Modeled after DEC's FN$HEX function, WL$OCTAL permits the user to translate a decimal value into a string representing the octal equivalent. This can be particularly useful when dealing with UIC's. DTR> PRINT WL$OCTAL(16) WL$OCTAL 20 WL$POWER This function simply raises a value to a power. Two real number arguments are required, the base and the exponent. DTR> PRINT WL$POWER(4.0,0.5), WL$POWER(5,3) WL$POWER WL$POWER 2.0000E+00 1.2500E+02 WL$RANDOM This function returns a random number. A single argument which is a longword "seed" value is required. The RTL function MTH$RANDOM then computes a random value. The function can be useful in statistical calculations requiring many iterations to compute probabilities. WL$RENAME_FILE As the name implies, this function is used to rename files. It requires two arguments, both TEXT variables, which contain the old and new file specifications respectively. DTR> WL$RENAME_FILE(old_file_spec, new_file_spec) WL$WAIT This function takes a single argument, a floating value representing a specified number of seconds. The function will then hibernate the process for the specified time. DTR> WL$WAIT(5) !Wait 5 seconds This function can be used in applications where several reports or plots are created sequential and displayed on the screen. If placed between report or plot statements, a pre-defined viewing time can be programmed into the procedure. Generating Function Help Digital supplies help text for all of the UDF's that are supplied with the installation kit. By insuring that UDF's not supplied by Digital can be identified (via our naming convention), we are able to automatically generate help file source text for these functions. The following procedure generates help file source text for our site-specific UDF's. DEFINE PROCEDURE MAKE_FUNCTION_HELP ! ! This procedure generates help file source text for Warner Lambert ! UDF's. ! ! Written by: Donald E. Stern, Jr. ! READY DTR_FUNCTIONS SHARED ! ON WL_FUNCTIONS.HLP ! FOR DTR_FUNCTIONS WITH DTR_FUNCTION_NAME STARTING "WL" BEGIN ! Print the comments about the function PRINT "2 "|DTR_FUNCTION_NAME, SKIP 2, FUNCTION_DESCRIPTION (-),SKIP 2, OUT_ARG_DESCRIPTION (-), SKIP 2,"Arguments:", SKIP 1, ALL " "|IN_ARG_DESCRIPTION (-), SKIP OF IN_ARGS, SKIP END END-PROCEDURE The following is excerpted from the file WL_FUNCTIONS.HLP which was generated using this procedure. : : 2 WL$DELETE_FILE Delete a file No output Arguments: Input is a filename to delete : : Using the following command one can extract Digital function help from the Datatrieve help library SYS$HELP:DTRHELP.HLB. $ LIB/HELP/EXT=FUNCTIONS SYS$HELP:DTRHELP DEC_FUNCTIONS Our help (WL_FUNCTIONS.HLP) can be concatenated with the Digital function help (DEC_FUNCTIONS.HLP) into a single file (FUNCTIONS.HLP) using the following DCL command. $ COPY/CONC DEC_FUNCTIONS.HLP,WL_FUNCTIONS.HLP FUNCTIONS.HLP This new help text is used to update the Datatrieve help library by the following command. $ LIB/LOG/HELP/REP SYS$HELP:DTRHELP FUNCTIONS Summary User Defined Functions are one way in which the functionality of VAX Datatrieve can be greatly extended. One need not be a MACRO programmer to implement UDFs. The "cookbook" procedure described in the Datatrieve documentation can be followed or a system such as the one described here can be implemented. Appendix I - Data Entry Routines DEFINE PROCEDURE ADD_DTR_FUNCTIONS ! ! This procedures readies the necessary domains and calls ! the ADD_DTR_FUNCTION procedure 1 or more times to add new ! definitions for Datatrieve User Defined Functions. ! ! Written by: Donald E. Stern, Jr. ! Warner Lambert Company ! 10 Webster Road ! Milford, CT 06460 ! ! READY DTR_FUNCTION_INFO SHARED WRITE READY DTR_FUNCTION_INPUTS SHARED WRITE DECLARE MORE PIC X. ! ! Shorthand for where we put User Defined DTR stuff. FN$CREATE_LOG("SCHICK$DTR","SCHICK$DISK:[DTRLIB]") MORE = "Y" WHILE MORE="Y" BEGIN :ADD_DTR_FUNCTION MORE=FN$UPCASE(*.MORE) END END-PROCEDURE DEFINE PROCEDURE ADD_DTR_FUNCTION ! ! This procedure is used to update the DTR_FUNCTIONS.DAT ! data file which all the necessary data to construct the ! DTRFUN.MAR file needed to add User Defined Functions ! (UDF's) to Datatrieve. ! ! NOTE: The domains DTR_FUNCTION_INFO and ! DTR_FUNCTION_INPUTS must be readed for WRITE ! access before invoking this procedure. ! ! ! Written by: Donald E. Stern, Jr. ! Warner Lambert Company ! 10 Webster Road ! Milford, CT 06460 ! ! !Create variables to contain data passed back from FMS ! DECLARE FNAME PIC X(31). DECLARE NARG BYTE. DECLARE ARGNM BYTE. ! ARGNM=0 ! ! Shorthand for where all our UDF stuff is. ! FN$CREATE_LOG("SCHICK$DTR","SCHICK$DISK:[DTRLIB]") ! ! Loop to update DTR_FUNCTION_INFO (1 record/UDF) BEGIN STORE DTR_FUNCTION_INFO USING DISPLAY_FORM DTR_FUNCTION_ADD IN SCHICK$DTR:DTR_FUNCTIONS RETRIEVE USING BEGIN FNAME = GET_FORM NAME DTR_FUNCTION_NAME = FNAME FUNCTION_DESCRIPTION = GET_FORM FUN_DESC EXT_FUNCTION_NAME = GET_FORM EXTERNAL OUT_ARG_TYPE = GET_FORM OUT_TYPE OUT_ARG_DTYPE = GET_FORM OUT_DTYPE OUT_ARG_DESCRIPTION = GET_FORM OUT_DESC EDIT_STR = GET_FORM EDT_STR QUERY_HDR = GET_FORM QRY_HDR NOVALUE = GET_FORM NOVAL NO_OPTIMIZE = GET_FORM NOOPT NARG = GET_FORM NARGS IN_COUNT = NARG END REPEAT NARG !Loop to update DTR_FUNCTION_INPUTS BEGIN !Contains 0-n records/UDF ARGNM = ARGNM + 1 STORE DTR_FUNCTION_INPUTS USING DISPLAY_FORM DTR_FUNCTION_ADD_INARGS IN SCHICK$DTR:DTR_FUNCTIONS USING BEGIN PUT_FORM NAME = FNAME PUT_FORM ARGNUM = ARGNM END RETRIEVE USING BEGIN DTR_FUNCTION_NAME = FNAME IN_ARG_TYPE = GET_FORM IN_TYPE IN_ARG_DESCRIPTION = GET_FORM IN_DESC IN_ARG_DTYPE = GET_FORM IN_DTYPE ORDER = GET_FORM ARG_ORDER OUT_PUT = GET_FORM OUTPUT ALL_LEN = GET_FORM ALLLEN END END END END-PROCEDURE Appendix II - Routines to Create DTRFND.MAR File DEFINE PROCEDURE MAKE_DTRFND ! ! This procedure re-creates the MACRO file DTRFND.MAR ! ! Supplied by: Philip A. Naecker ! Consulting Engineer ! Altadena, CA ! READY DTR_FUNCTIONS SHARED SET COLUMNS_PAGE = 132 ON DTRFND.MAR BEGIN PRINT - ".TITLE DTRFND VAX-11 Datatrieve Function Definitions", SKIP, ";+++++++++++++++++++++++++++++++++++++++++++++++++++", SKIP, ";", SKIP, "; F U N C T I O N D E F I N I T I O N S", SKIP, ";", SKIP, ";---------------------------------------------------", SKIP 2, ".PSECT FND,NOWRT,SHR,PIC,2", SKIP 1, ".LIBRARY /DTR$LIBRARY:DTRFNLB/", SKIP 1, ".LIBRARY /SYS$LIBRARY:STARLET/", SKIP 1, ";.SHOW EXPANSIONS", SKIP 1, "$DSCDEF", SKIP 1, "$DTR$FUN_INIT", SKIP 4 ! ! Print all of the functions ! FOR DTR_FUNCTIONS :PRINT_FUNCTION ! ! Print the trailer ! PRINT "$DTR$FUN_FINI", SKIP 2, ".END" END; END-PROCEDURE DEFINE PROCEDURE PRINT_FUNCTION ! ! Print a single function definition in DTRFND.MAR ! ! Supplied by: Philip A. Naecker ! Consulting Engineer ! Altadena, CA ! ! Modified by: Donald E. Stern, Jr. ! Warner Lambert Company ! 10 Webster Road ! Milford, CT 06460 ! BEGIN ! Print the comments about the function PRINT "; "|DTR_FUNCTION_NAME|||"- "| FUNCTION_DESCRIPTION, SKIP, ";", SKIP, "; "|OUT_ARG_DESCRIPTION, SKIP, ALL "; "|IN_ARG_DESCRIPTION, SKIP OF IN_ARGS, SKIP ! The opening line PRINT "$DTR$FUN_DEF"|||DTR_FUNCTION_NAME|| ", "|EXT_FUNCTION_NAME||", "|IN_COUNT ! The output argument PRINT " $DTR$FUN_OUT_ARG TYPE = "| OUT_ARG_TYPE VIA FUN_TYPE_TABLE|| IF (OUT_ARG_TYPE EQ "STATUS","INPUT") THEN " " ELSE ", DTYPE = DSC$K_DTYPE_"| OUT_ARG_DTYPE VIA DTYPE_VALUE_TO_NAME ! If the function is a novalue function, say so. IF (NOVALUE EQ "Y") THEN PRINT " $DTR$FUN_NOVALUE" ! If the function is a nooptimize function, say so IF (NO_OPTIMIZE EQ "Y") THEN PRINT " $DTR$FUN_NOOPTIMIZE" ! Do the edit-string and query-header IF (EDIT_STR NOT MISSING) THEN PRINT " $DTR$FUN_EDIT_STRING ^\"|| EDIT_STR||"\" IF (HDR NOT MISSING) THEN PRINT " $DTR$FUN_HEADER HDR = <"||HDR||">" ! OK, now for the input arguments FOR A IN IN_ARGS CHOICE (IN_ARG_TYPE = "TEXT") THEN PRINT " $DTR$FUN_IN_ARG TYPE ="||| (IN_ARG_TYPE VIA FUN_TYPE_TABLE)|| (IF (ALL_LEN EQ 0) THEN " " ELSE ",ALL_LEN = "|ALL_LEN)| (CHOICE (ORDER NE 0) THEN ", ORDER = "|ORDER (OUT_PUT EQ "Y") THEN ", OUT_PUT = TRUE" ELSE ";;; illegal OUTPUT or ORDER" END_CHOICE) (IN_ARG_TYPE = "VALUE") THEN PRINT " $DTR$FUN_IN_ARG TYPE ="||| (IN_ARG_TYPE VIA FUN_TYPE_TABLE)|| ", DTYPE = DSC$K_DTYPE_"| IN_ARG_DTYPE VIA DTYPE_VALUE_TO_NAME||", ORDER = "| ORDER (IN_ARG_TYPE = "NULL") THEN PRINT " $DTR$FUN_IN_ARG TYPE ="||| (IN_ARG_TYPE VIA FUN_TYPE_TABLE) (IN_ARG_TYPE = "REF", "DESC") THEN PRINT " $DTR$FUN_IN_ARG TYPE ="||| (IN_ARG_TYPE VIA FUN_TYPE_TABLE)|| ", DTYPE = DSC$K_DTYPE_"| IN_ARG_DTYPE VIA DTYPE_VALUE_TO_NAME|| (CHOICE (ORDER NE 0) THEN ", ORDER = "| ORDER (OUT_PUT EQ "Y") THEN ", OUT_PUT = TRUE" ELSE ";;; Illegal OUTPUT or ORDER" END_CHOICE) ELSE PRINT ";;; Illegal input type" END_CHOICE PRINT "$DTR$FUN_END_DEF", SKIP END END-PROCEDURE DEFINE PROCEDURE MAKE_COMMAND_FILE ON CHECK.COM BEGIN PRINT "$MAC/LIS DTRFND" PRINT "$COPY DTRFND.MAR, DTRFND.LIS, DTRFND.OBJ -" PRINT " SCHICK$DISK:[DTRLIB]*/LOG" PRINT "$LIBR/LOG/REP SCHICK$DISK:[SCHICK.DTRLIB]DTRFUN -" PRINT " SCHICK$DISK:[DTRLIB]DTRFND" END END-PROCEDURE Appendix III - WL$x Function Definitions from DTRFND.MAR The following was extracted from the file DTRFND.MAR. It provides the precise definition for each of the site-specific UDF discussed above. ; WL$CHAR - convert an ASCII Code to an ASCII Character ; ; output is a one character string ; ; input is an unsigned byte ASCII code $DTR$FUN_DEF WL$CHAR, LIB$CHAR, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_IN_ARG TYPE = FUN$K_TEXT, OUT_PUT = TRUE $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_BU, ORDER = 1 $DTR$FUN_END_DEF ; WL$DAY - returns the number of days since the base date 17-Nov-1858 ; ; output is a longword integer cont. the days since base date ; ; input is a binary quadword date $DTR$FUN_DEF WL$DAY, LIB$DAY, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_L, OUT_PUT = TRUE $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_ADT, ORDER = 1 $DTR$FUN_END_DEF ; WL$DAY_OF_WEEK - returns a numeric day of the week for a date/time ; ; output is an unsigned longword value between 1 and 7 ; input is a 64-bit date/time ; $DTR$FUN_DEF WL$DAY_OF_WEEK, LIB$DAY_OF_WEEK, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_ADT, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_L, OUT_PUT = TRUE $DTR$FUN_END_DEF ; WL$DELETE_FILE - Delet a file ; ; No output ; Input is a filename to delete $DTR$FUN_DEF WL$DELETE_FILE, LIB$DELETE_FILE, 1 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_NOOPTIMIZE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_END_DEF ; WL$DELETE_LOGICAL - deletes a supervisor-mode logical from a specified table ; ; no output ; argument 1 is a char. string containing the logical name ; arg. 2 is a char. string cont. the logical name table $DTR$FUN_DEF WL$DELETE_LOGICAL, LIB$DELETE_LOGICAL, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_NOOPTIMIZE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 2 $DTR$FUN_END_DEF ; WL$EDT - Edit an ASCII file ; ; No output ; input is a filename passed by descriptor $DTR$FUN_DEF WL$EDT, EDT$EDIT, 1 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_NOOPTIMIZE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_END_DEF ; WL$GET_SYMBOL - returns the value of a CLI symbol as a string ; ; output is a character string passed by desc. ; arg. 1 is a char. string cont. the symbol name ; $DTR$FUN_DEF WL$GET_SYMBOL, LIB$GET_SYMBOL, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_TEXT, OUT_PUT = TRUE $DTR$FUN_END_DEF ; WL$OCTAL - convert an unsigned integer longword to an octal char. strg. ; ; output is a character string representing an octal value ; input is an unsigned integer longword passed by reference ; $DTR$FUN_DEF WL$OCTAL, OTS$CVT_L_TO, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_EDIT_STRING ^\X(8)\ $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_L, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_TEXT, ALL_LEN = 8, OUT_PUT = TRUE $DTR$FUN_END_DEF ; WL$POWER - computes the value of a number raised to a power ; ; output is a real number ; argument 1 is the base ; argument 2 is a real exponent $DTR$FUN_DEF WL$POWER, OTS$POWRR, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_VALUE, DTYPE = DSC$K_DTYPE_F $DTR$FUN_IN_ARG TYPE = FUN$K_VALUE, DTYPE = DSC$K_DTYPE_F, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_VALUE, DTYPE = DSC$K_DTYPE_F, ORDER = 2 $DTR$FUN_END_DEF ; WL$RANDOM - a random number generator ; ; output is an F-floating random number ; input is an unsigned integer longword $DTR$FUN_DEF WL$RANDOM, MTH$RANDOM, 1 $DTR$FUN_OUT_ARG TYPE = FUN$K_VALUE, DTYPE = DSC$K_DTYPE_F $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_L, ORDER = 1 $DTR$FUN_END_DEF ; WL$RENAME_FILE - Renames a file ; ; No output ; Argument 1 is the source filename passed by descriptor ; Argument 2 is the new filename passed by descriptor $DTR$FUN_DEF WL$RENAME_FILE, LIB$RENAME_FILE, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_NOOPTIMIZE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 2 $DTR$FUN_END_DEF ; WL$SET_LOGICAL - (re)defines a supervisor mode logical in a specified table ; ; no output ; arg. 1 is a char. string containing the logical name ; arg. 2 is a char string containing the value to assign ; arg. 3 is a char. string cont. the name of the table $DTR$FUN_DEF WL$SET_LOGICAL, LIB$SET_LOGICAL, 3 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_NOOPTIMIZE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 2 $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 3 $DTR$FUN_END_DEF ; WL$SET_SYMBOL - define or redefine a CLI symbol ; ; no output ; arg. 1 is a string descriptor containing the CLI symbol ; arg. 2 is a string descriptor cont. the CLI symbol value $DTR$FUN_DEF WL$SET_SYMBOL, LIB$SET_SYMBOL, 2 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 1 $DTR$FUN_IN_ARG TYPE = FUN$K_DESC, DTYPE = DSC$K_DTYPE_T, ORDER = 2 $DTR$FUN_END_DEF ; WL$WAIT - places current process in hibernation for specified time ; ; no output ; input is the number of seconds to wait - F-floating by ref. $DTR$FUN_DEF WL$WAIT, LIB$WAIT, 1 $DTR$FUN_OUT_ARG TYPE = FUN$K_STATUS $DTR$FUN_NOVALUE $DTR$FUN_IN_ARG TYPE = FUN$K_REF, DTYPE = DSC$K_DTYPE_F, ORDER = 1 $DTR$FUN_END_DEF Appendix IV - Database for Valid Datatypes DEFINE TABLE DTYPE_NAME_TO_VALUE FROM DTYPS USING NAME : VALUE END_TABLE DEFINE TABLE DTYPE_VALUE_TO_NAME FROM DTYPS USING VALUE : NAME END_TABLE DEFINE DOMAIN DTYPS USING DTYP_REC ON SCHICK$DISK:[DTRLIB]DTYPE.DAT; DEFINE RECORD DTYP_REC 01 DTYPE. 03 VALUE PIC 99. 03 NAME PIC X(4). 03 DESC PIC X(60). ; Value Name Description 00 Z unspecified 01 V bit - an aligned bit string 02 BU byte logical - 8-bit unsigned quantity 03 WU word logical - 16-bit unsigned quantity 04 LU longword logical - 32-bit unsigned quantity 05 QU quadword logical - 64-bit unsigned quantity 06 B byte integer - 8-bit signed 2's complement integer 07 W word integer - 16-bit signed 2's-complement integer 08 L longword integer - 32-bit signed 2's-complement integer 09 Q quadword integer - 64-bit signed 2's-complement integer 10 F F-floating - 32-bit single precision real number 11 D D-floating - 64-bit double precision 12 FC F-floating complex - low address real, high address imag 13 DC D-floating complex- Pair of D-float. (low real, high imag.) 14 T char. coded text - string data type 15 NU numeric string, unsigned 16 NL numeric string, left separate sign 17 NLO numeric string, left overpunched sign 18 NR numeric string, right separate sign 19 NRO numeric string, right overpunched sign 20 NZ numeric string, zoned sign 21 P packed decimal string 22 ZI sequence of instructions 23 ZEM procedure entry mask 24 DSC descriptor - levels of descriptors are allowed 25 OU octaword logical - 128-bit unsigned quantity 26 O octaword integer - 128-bit signed 2's complement integer 27 G G-floating - 64-bit double precision number 28 H H-floating - 128-bit quad precision real number 29 GC G-floating complex- Pair of G-float. (low real, high imag.) 30 HC H-floating complex- Pair of H-float. (low real, high imag.) 31 CIT COBOL Interm. Temp. - 18-digit norm. dec. fract. 2-dig exp. 32 BPV bound procedure value 33 BLV bound label value 34 VU bit unaligned - data are 0 to 2**16-1 contiguous bits 35 ADT absolute date and time 37 VT varying character-coded text Appendix V - Table of Function/Argument Types DEFINE TABLE FUN_TYPE_TABLE "STATUS" : "FUN$K_STATUS" "INPUT" : "FUN$K_INPUT" "VALUE" : "FUN$K_VALUE" "REF" : "FUN$K_REF" "DESC" : "FUN$K_DESC" "TEXT" : "FUN$K_TEXT" "NULL" : "FUN$K_NULL" END_TABLE