A-Shell 4.7(813) added a new Basic language statement which allows you to call an external subroutine whose name is resolved at runtime rather than at compile time. The statement is identical in syntax and usage to XCALL, except that "XCALL" is replaced by "VXCALL", and the name of the subroutine, which must be a literal in the case of XCALL, must be a quoted string, string variable, or expression. Here are some examples:
map1 SBRNAM$,S,6,"HELLO"
VXCALL SBRNAM$,ARG1,ARG2,... ! (xcall HELLO,...)
VXCALL "HELLO",ARG1,ARG2,... ! (xcall HELLO,...)
VXCALL SBRNAM$+"1",ARG1,ARG2,... ! (xcall HELLO1,...)
As with other A-Shell extensions to Basic, you must compile your programs with the /X:2 switch to enable the use of the VXCALL statement.
VXCALL can be used equally well with embedded subroutines (those written in C and linked into A-Shell) and external SBX routines. However, its usefulness is magnified in the case of SBX routines, providing an almost open-ended mechanism to customize application behavior at runtime. The following examples will help illustrate this.
First, let’s consider an invoicing module installed in many businesses. Unfortunately, many businesses are particular about their invoices, perhaps requiring a special form, or wanting their own logo, or custom messages to be printed at the bottom, etc. Rather than having to include a bunch of "IF" conditions and a bunch of different routines within the invoice program (with only one being used at a particular site), you could just design your invoice program to assemble the necessary line items and header information into a standardized structure, and then pass it via RXCALL to an invoice formatting subroutine whose name was a function of the site or client ID. For example:
map1 INV'DATA ! (uniform structure with invoice data)
map2 INV'HDR'DATA
map3 ...
map3 ...
map2 INV'LINE'ITEMS(500)
map3 ITEM'NO,S,10
map3 ...
<load up INV'DATA structure...>
VXCALL SITE'ID$,OPCODE'INV,INV'DATA ! (format & print invoice)
In the above example, we are passing an "opcode" variable to the SITE’ID$ subroutine to allow for the possibility of combining several different customization functions within a single subroutine. The developer/distributor of the software could then release source code to a standard version of the customization module (renamed to match the SITE’ID$), and allow each site to customize it as they choose. The fact that the A-Shell runtime system contains the compiler, and that the linking and binding for such subroutines is all done at runtime, makes this particularly feasible. Naturally, there would be a training issue, but in some cases that might create an opportunity to engage the customer’s desire for customization and earn additional revenues at the same time. Even if the developer/distributor does all the customization on behalf of the client, this mechanism provides a very useful mechanism for modularization, isolating the code that is site-specific, from the core of the application.
As a second example, consider the COMMAND=SBX:<sbxname> parameter in the A-Shell printer initialization files. Briefly, what this statement does is cause the print spooler interface to pass the print file to the specified subroutine for processing, either before or in lieu of sending it to a printer. Without the VXCALL mechanism for binding the subroutine name at runtime, this would be impossible.
As a third and final example, VXCALL opens the possibility for the creation of a generic front-end subroutine that handled some kind of pre-processing or interfacing function that you wish to apply to a range of subroutines, some of which you may not have the ability to modifiy directly because they are embedded within A-Shell. Why would you want to do such a thing? One reason might be for security or licensing. Let’s say you have a series of data access or display subroutines, and then your industry (for example, the health care industry) decides to impose (or the government forcefully imposes on them) a regime of strict security requirements to protect the privacy of data. One way to deal with such a requirement would be to develop a single security package that could then be wrapped around a variety of subroutines that had anything to do with data access. For example, if you called your wrapper routine SECURE, you might use it with existing subroutines such as SERCH (to lookup records) and DSPLY (to format/display data) as follows:
xcall SECURE,"DSPLY",XMAX,ROW,COL,DECMAL,OPTION,1
xcall SECURE,"SERCH",CH,REC,KEY,...
The observant reader will note that we didn’t use VXCALL in the above statements, but the point is that our hypothetical SECURE.SBX module would need to use VXCALL to call the routine specified in the first argument. Otherwise, we would need a different version of SECURE.SBX for every other subroutine we wanted to apply it to.
Naturally, this approach introduces another layer of overhead on the underlying subroutines, but virtually all other industry-standard approaches to creating security wrappers around data objects involve substantial overhead as well. It should also be noted that the approach doesn’t provide a very thorough level of data security, since the data itself can presumably be copied and accessed by rogue parties, without using the hypothetical SECURE routine. To protect against that kind of access, you would have to encrypt your data, and build the decryption logic into the SECURE routine itself.
Update Note: A-Shell Build 1186 of June 2010
Names up to 10 characters are now supported. Prior to this update, while the compiler didn't/couldn't complain, the runtime system looked at only the first 6 characters.
Note that the 10 character limit is not related to the RUN format but to the existing 10.3 framework for files loaded into USRMEM and which benefit from the emulation of the AMOS-style file system. When those get expanded, the VXCALL name limit will expand with them.