Ring/Lessons/Extension using the C/C++ languages

Extension using the C/C++ languages
We can extend the Ring Virtual Machine (RingVM) by adding new functions written in the C programming language or C++.

The RingVM comes with many functions written in C that we can call like any Ring function.

We can extend the language by writing new functions then rebuilding the RingVM again, or we can create shared library (DLL/So) file to extend the RingVM without the need to rebuild it.

The Ring language source code comes with two files to add new modules to the RingVM, ring_ext.h and ring_ext.c

ring_ext.h
The file ring_ext.h contains constants that we can change to include/exclude modules during the build process.

ring_ext.c
The file ring_ext.c check constants defined in ring_ext.h before calling the start-up function in each module.

Each module contains a function that register the module functions in the RingVM.

Module Organization
Each module starts by include the ring header file (ring.h). This files contains the Ring API that we can use to extend the RingVM.

Each module comes with a function to register the module functions in the RingVM The registration is done by using ring_vm_funcregister function.

The ring_vm_funcregister function takes two parameters, the first is the function name that will be used by Ring programs to call the function. The second parameter is the function pointer in the C program.

for example, the ring_vmmath.c module contains the next code to register the module functions

.. tip:: Remember that the function ring_vm_math_loadfunctions will be called by the ring_vm_extension function (in the ring_ext.c file).

Function Structure
Each module function may contains the next steps

1 - Check Parameters Count

2 - Check Parameters Type

3 - Get Parameters Values

4 - Execute Code/Call Functions

5 - Return Value

The structure is very similar to any function (Input - Process - Output) But here we will use the Ring API for the steps 1,2,3 and 5.

Check Parameters Count
We can check the parameters count using the RING_API_PARACOUNT macro.

We can compare RING_API_PARACOUNT with any numeric value using == or != operators.

Example:

Example:

Display Error Message
We can display error messages using the RING_API_ERROR function.

The function will display the error and end the execution of the program.

.. note:: the behaviour of this function can be changed by the Ring code using Try/Catch/Done statements, so in your C code, use Return after this function.

Syntax:

The Ring API comes with some of predefined error messages that we can use

Check Parameters Type
We can check the parameter type using the next functions

The output of these functions will be 1 (True) or 0 (False).

Get Parameters Values
We can get paramters values using the next functions

Return Value
We can return values from our function using the next functions.

Function Prototype
When we define new function to be used for RingVM extension, we use the next prototype

Sin Function Implementation
The next code represents the sin function implementation using the Ring API and the sin C function.

Fopen and Fclose Functions Implementation
The next code represents the fopen function implementation using the Ring API and the fopen C Function.

The function takes two parameters, the first parameter is the file name as string. The second parameter is the mode as string.

In the file ring_vmfile.h we have some constants to use as the pointer type like

The function implementation in ring_vmfile.c

The next code represents the fclose function implementation

From fopen and fclose implementation we learned

1 - how to return C pointer using RING_API_RETCPOINTER function

2 - how to check if the parameter is a pointer using the RING_API_ISPOINTER function

3 - how to get C pointer value using the RING_API_GETCPOINTER function

4 - how to set the C pointer variable (in RingVM) to NULL using the RING_API_SETNULLPOINTER function

Ring API - List Functions
In this section we will learn about the list functions provided by the Ring API to create new lists and manipulate the list items.

Ring API - String Functions
In this section we will learn about the string functions provided by the Ring API to create new string and manipulate the string content.

MySQL_Columns Function Implementation
The next code presents the MySQL_Columns function implementation.

This function returns table columns information.

Lists are of type List, in the previoud function we declared two pointers of type List using List *pList, *pList2; .. note:: The function uses RING_API_NEWLIST to create new list instead of ring_list_new to create the list in Temp. Memory related to the function scope. This way we can return the list from the function. Also we don't delete the list, if it's stored in a variable by Ring Code it will be saved, if not it will be automatically deleted by RingVM.

The list can contains sub lists, we used the function ring_list_newlist to create a sublist.

The function ring_list_addstring is used to add string items to the list/sublist.

The function ring_list_adddouble is used to add numeric items to the list/sublist.

.. note:: All numeric items in lists returned from RingVM extension functions must be of type double and added to the list using ring_list_adddouble function.

We return the list from the extension function using the RING_API_RETLIST function.

Dynamic/Shared Libraries (DLL/So) and LoadLib function
Instead of rebuilding the RingVM after writing new functions using C/C++ and the Ring API, we can create a DLL/So file and dynamically use the functions provided by this file in the runtime using the LoadLib function.

Dynamic library example in C

the idea is to create the ringlib_init function, this function will be called by the RingVM when we use the generated DLL file though the LoadLib function.

Inside the ringlib_init function we can register the module function or call a function that do the registration process for all of the module functions.

The next Ring code demonstrates how to use the DLL library during the runtime.

Output: