FlashBASIC C Functions Overview

C functions can be called from a FlashBASIC program or subroutine using a syntax similar to that of normal C.

For Windows: The FlashBASIC program or subroutine must be compiled with the optimized (o option.

NOTE

See the Reference Manual for your specific operating system for information on any C Functions that are not represented in this guide.

Commonly used functions are included in the run time package and require no special linking. These functions are referred to as built-in functions. A user-defined function can also be included in a FlashBASIC application by linking it with the monitor, thus making a user-defined built-in function.

C function calls can be embedded in FlashBASIC expressions, FlashBASIC statements or can be used as arguments to other C function calls. Combined size of all parameters passed cannot exceed 32 KB. This size can be changed, however, by the TCL set-cmem command.

If a type specifier is omitted before an argument name, the argument is assumed to be of type integer when arg is a number, or to be of type pointer when arg is a dynamic array (string). If type is omitted before the function name, the function is assumed to be of type integer.

arg0...argn are the optional arguments to the function; up to 15 arguments are supported.

The return type of a function is void if the function is not part of an assignment statement or used as an argument to another C function or FlashBASIC statement. Whenever the return value of a function can be neglected, the type can be overridden by (void).

When a call to a function is made:

ptr=(char*)%malloc(1024)

if ptr > 0 then print ’ok’

The only valid form is to test for ptr = 0 or ptr # 0.

Argument Types

These argument types are supported:

Argument Type

Description

<nothing>

Default. If arg is a number, an (int) is passed to the function. If arg is a dynamic array (string), a pointer to the first character of the string is passed to the function. If arg is a dimensioned array, a pointer to an image of the dimensioned array is passed to the function. See Passing Dimensioned Arrays below.

(int)

Integer. The arg is divided by the precision factor and passed to the C function. Integers are 32-bit signed elements.

(char)

Character. If arg is a dynamic array (string), the first character is passed to the C function. If arg is a number it is divided by the precision factor and the result is truncated to 8 bits and passed to the C function.

(char*)

Pointer. The arg is a number that is passed to the C function without being divided by the precision factor. The only legal use of this type is to pass a null pointer or a pointer returned by a previous call to a C function to another C function.

All types, except pointers can be prefixed by the keyword unsigned, (unsigned char, for example).

NOTE

The precision factor is a number between 0 and 9, with 4 being the default value. When a number is divided by the precision factor, the number is actually being divided by 10 raised to the power of precision.

Passing Dimensioned Arrays

Dimensioned arrays of integers can be passed to an external C function. When the array is passed, the C function receives a pointer to the array and all the integers in the array are divided by the precision factor. If the array is multidimensional, the integers are organized column by column. For example, if we have an array that is dimensioned to (2, 5) in FlashBASIC, the values in the C array would be in this order: (1, 1), (2, 1), (1, 2), (2, 2), (1, 3), (2, 3), and so on.

Function Types

These function types are supported:

Function

Description

<nothing>

Default. The return value is assumed to be an integer. It is multiplied by the precision factor.

(void)

Return value is discarded. When prefixed with this type, the function cannot be part of an assignment or be used as an argument to another C function or FlashBASIC statement or function.

(int)

Integer. The return value is a signed integer. It is multiplied by the precision factor.

(char)

Character. The return value is stored as a dynamic array containing only one character.

(char*)

Pointer. The return value is stored without being multiplied by the precision factor. The only legal use of this type is to store a pointer that for use as an argument to another C function.

’Address of’ Unary Operator

The C unary operator, &, is used to pass the address of an integer to an external C function. This is the only valid form. Note that FlashBASIC converts numbers that are too large into strings. In this case, the C function would receive a pointer to a character instead of a pointer to an integer.

Space Reserve Command

When a FlashBASIC variable (a dynamic array or an element of a one or two-dimensional array) is used to store data returned by a call to a C function (by means of a pointer passed as an argument), the FlashBASIC variable must have been assigned a size before the call to the function. This needs to be done because C has no notion of dynamic arrays. If a size is not assigned before the result of a C function call is stored in the variable, the data is truncated. For example:

char var[size] {,var[size],...}

This reserves at least size bytes for var. size can be a constant or an expression. var can be a dynamic array or an element of a one or two-dimensional array. After reserving space for var, the content of the variable is undefined.

If a string longer than size is assigned to a variable, it is truncated and the characters beyond the given size are ignored. If a string shorter than size is assigned to a variable, the remainder of the char buffer remains undefined. The content of the buffer, including how it is terminated, is determined by the function. A terminator is not automatically added.

The buffer should not be used for any purpose other than as a C function call parameter. Doing so may change the internal format of the variable such that it is no longer a char buffer. If the data in the buffer needs further processing by BASIC, it should be copied to another variable and the copy used. For an example, see the %read() Function example code.

Static Data

When using user-defined built-in functions, static data defined as part of a user-defined function remains valid as long as the D3 process is not disconnected from the virtual machine. This is true even if the FlashBASIC program is finished executing and has returned to TCL. The scope of static data lasts longer than in conventional UNIX or Windows programs.

Because static data takes up space in the data section of each D3 process (therefore main memory), it is not advisable to have large amounts of static space.

Includes

The header files below are provided in the file bp,unix.h, in the dm account.

errno.h

errno values

fcntl.h

Codes for %open(), %creat

ipc.h

Semaphores, shared memory, messages

mode.h

File access codes

sem.h

Semaphore operations

signal.h

UNIX signal numbers

These rules apply when making a call to a C function:

Syntax

{variable =}{(type)}%function({{(type)} arg0 {,...{(type)} argn}})

Creating User-Defined C Functions (D3 UNIX)

A user-defined C function can be incorporated in the D3 monitor, thus making C functions available to all applications running on the system.

This way of customizing the monitor should be reserved to functions that are widely used in the applications running on the system (such as a math package, graphics, communications, and so on). It is a relatively complex procedure that should be attempted only by programmers experienced both in D3 and UNIX.

The main advantage of this procedure is efficiency. The cost, however, is the loss of portability to non-D3 UNIX platforms. Also, the user-defined built-in function must be integrated in the monitor at every new release.

Integrating a C function in the monitor requires:

A description of the necessary procedures is shown in the example below. The tools used in this section are described completely under their respective entries in the documentation.

WARNING

It must be emphasized that, especially while debugging with UNIX debuggers, changing data in the D3 environment can cause damage to the database.

Most of the procedures below can be done from TCL (by prefixing UNIX commands with an !). The D3 process has to be stopped (disconnected), however, when the new monitor is about to be created, because most UNIX versions do not allow rebuilding an object module that is currently being executed.

To add a new function to the monitor:

  1. Logon to the dm account.

  2. Add the new module to the FlashBASIC-C interface. Type:

  3. addbi fpadd fpsub fpmul fpdiv

    The TCL addbi command adds the functions to the item dm,messages, user.builtin and creates and compiles the file px_user.c which is the built-in user branch table.

    This step needs to be done only once.

  4. Edit and compile the C program. After entering the C program, compile it. Type:

  5. !cc -c fp.c

    This creates the module fp.o.

  6. Add the new module and the User branch table to the user function library. Type:

  7. !ar vru libgmu.a fp.o px_user.o

  8. Disconnect the current D3 Process.

  9. If the current line is line 0, the D3 virtual machine shuts down. At this stage, because user processes normally execute the reference monitor /usr/bin/d3, it is not necessary to stop the virtual machine.

  10. Return to the shell. Type:

  11. disc

  12. Build the new monitor. Type:

  13. make -f /usr/lib/pick/Makefile

    This creates a monitor named d3 on the current directory. If errors occur during its creation, it may be necessary to make modifications to the Makefile.

  14. Test the new monitor

  15. Generally, it is not necessary to shutdown the D3 virtual machine to start a user process on a new monitor. The new monitor can be executed by one or more user processes for test purpose.

  16. Type:

  17. ./d3

    This starts a user process executing the new monitor. To make any changes, repeat the procedure from steps 3 to 8 until the C function is working properly. Debugging can be done with the usual UNIX debuggers like sdb or dbx.

  18. Logon to dm. Enter this FlashBASIC program:

  19. bp fpdiv:

    cfunction unix.builtin, user.builtin

    * Reserve space for the resulting string char result[64]

    * Call the C function (no return code)

    %fpdiv("1.23e-9", "1.2e-3", result, 64)

    * Extract result (0 terminated string)

    print 'Res=':field(result,char(0),1)

  20. Compile and run it:

  21. compile bp fpdiv

    run bp fpdiv

    Res=1.02500000000000013890527183341e-06

  22. Repeat steps 3 to 8 until the new function works properly.

  23. Move the monitor to the working directory.

  24. When the new monitor is properly tested, it can be moved to the common directory, where Users can access it. Copying the new monitor must be done as super-user (root) because the directory is write protected.

    su (enter password)

    chmod 06755 d3

    chown root:bin d3

    cp d3 /usr/bin

  25. Shutdown and reboot the D3 virtual machine.

  26. User processes now execute the new monitor.

Example(s)

Consider the C functions below that perform the four basic operations on two strings, s1 and s2, representing floating point numbers in FORTRAN F-format or E-format ("[-]d.dddE[+-]dd"). A string, up to p characters long, representing the result, is returned into s3.

fp.c :

double atof();

fpadd(s1, s2, s3, p)

char *s1, *s2, *s3;

int p;

{

gcvt(atof(s1)+atof(s2), p, s3);

}

fpsub(s1, s2, s3, p)

char *s1, *s2, *s3;

int p;

{

gcvt(atof(s1)-atof(s2), p, s3);

}

fpmul(s1, s2, s3, p)

char *s1, *s2, *s3;

int p;

{

gcvt(atof(s1)*atof(s2), p, s3);

}

fpdiv(s1, s2, s3, p)

char *s1, *s2, *s3;

int p;

{

gcvt(atof(s1)/atof(s2), p, s3);

}

Creating User-Defined C Functions (D3 Windows)

The example below describes creating, adding, removing, loading and unloading a C DLL function in Visual Studio 2008.

Step 1: Create a new Project:

  1. From the Visual Studio startup panel, select the create Project option.

  2. Select the Visual C++ Project Type.

  3. Select the Win32 Project template.

  4. Specify a Name, Location and Solution Name and then click OK

  5. Click Next at the Custom Application Wizard Welcome screen.

  6. Specify the DLL Application Type.

  7. Select the Empty Project check box from Additional Options.

  8. Click Finish.

  9. The project is created.

Step 2: Create the user branch table (pxusrtbl.cpp)

  1. Log to the DM account in TCL and add the user built in functions with the addbi command. For example:

  2. Type the following command:

    addbi MyFunc (f

    to:C:/temp/CLoad/CLoad

    The to: path is the path you specified in the Location text box in step 4 above).

    The user branch table is created.

Step 3: Verify the user builtin functions

  1. Run the following command from TCL:

  2. ct messages user.builtin

        user.builtin

    001 15

    002 MyFunc]1

Step 4: Add the pxusrtbl.cpp to the project

  1. From the Solution Explorer, right-click Source Files and select Add -> Existing Item.

  2. Select pxusrtbl.cpp.

  3. Click Add.

Step 5: Create and add the C++ source code file

  1. From the Solution Explorer,  right-click Source Files and select Add -> New Item.

  2. Select C++ File.

  3. Give this file a name in the format (filename.c).

  4. Click Add.

  1. Open this source file and enter the C++ code.

  2. Code example:

    //Comment here

    int MyFunc(int x)

    {

    return x+1;

    }

Step 6: Set Compile options

  1. Select Project > Properties from the Visual Studio menu bar.

  2. Expand the Configuration Properties item.

  3. Expand the C++ item.

  4. Select the Code generation item.

  5. Click Runtime Library and specify the your Runtime Library:

  6. Click OK.

  7. Select File > Save All from the Visual Studio menu bar.

Step 7: Build the dll

  1. Select Build > Build CLoad.dll from the Visual Studio menu bar.

Step 8: Load the dll

  1. Log to the DM account in TCL and run the following command:

  2. nt_cload 15 C:/temp/CLoad/debug/CLoad.dll

    Note that the 15 is required.

    Note that you can only load 1 dll. As such, all functions must be contained within the specified dll.

Step 9: View the dll

  1. Run the following command from TCL to confirm the dll has been loaded:

  2. nt_cinfo 15

Step 10: Test the new function

  1. From TCL, test the function:

  2. u bp test.cload

    001 cfunction user.builtin

    002 print %MyFunc(3)

    compile bp test.cload (o

    run bp test.cload

    Note that the (o option for Flash compiling is required.

Step 10a: Rebuild using the non-debug run-time library if necessary.

  1. After verifying the dll is working properly, you may need to rebuild it for deployment to systems that do not have VC++ loaded. See step 6.

Step 11: To start all over

  1. Unload the dll.

  2. nt_cunload 15

  3. Delete messages user.builtin.

  4. Delete the project workspace directory.

  5. C:\temp\CLoad

See Also

%alarm() Function, %chdir() Function, %chmod() Function, %chown() Function, %close() Function, %creat() Function, %dup() Function, %fclose() Function, %fdopen() Function, %fgetc() Function, %fgets() Function, %fopen() Function, %fprintf() Function, %fputc() Function, %fputs() Function, %free() Function, %freopen() Function, %fsize() Function, %getenv() Function, %getpgrp() Function, %getpid() Function, %getppid() Function, %ioctl() Function, %kill() Function, %lseek() Function, %memcopy() Function, %memcpy() Function, %memxcpy() Function, %open() Function, %pause() Function, %pclose() Function, %pgetpid() Function, %popen() Function, %rdhex() Function, %read() Function, %semctl() Function, %shmat() Function, %shmdt() Function, %shmget() Function, %ttyname() Function, %unlink ()Function, %wait() Function, %whex() Function, %write() Function, @() Function, @am Function, abs() Function, access() Function, addbi Command, alpha() Function, ascii() Function, C Functions Overview, cfunction Statement, char() Function, col1() Function, col2() Function, cos() Function, count() Function, Creating User-Defined C Functions, date() Function, dcount() Function, delete() Function, dtx() Function, ebcdic() Function, error() Function, execute Statement, exp() Function, extract() Function, field() Function, FlashBASIC and BASIC Differences, fmt() Function, fold() Function, iconv() Function, index() Function, insert() Function, int() Function, len() Function, listbi Command, ln() Function, mod() Function, not() Function, num() Function, occurs() Function, oconv() Function, pwr() Function, rem() Function, replace() Function, rmbi Command, rnd() Function, scan() Function, sentence() Function, seq() Function, set-cmem Command, sin() Function, sort() Function, soundex() Function, space() Function, sqrt() Function, Statements and Functions, str() Function, sum() Function, system() Function, tan() Function, time() Function, timedate() Function, trim() Function, xtd() Function