Developer's guide for creating static libraries for Concept


Developer's guide for creating static
libraries for Concept

by Eduard Suica, (c)2006 RadGs Software


     Concept is a new way of programming, fully independent of the operating system. You can develop "special" libraries for Concept in any programming language that is capable to generate binary code. In the next article we'll take the example of C and will use the GNU G++/GCC compilers. The whole code is fully ANSI Compatible (which for Concept is a MUST).

     The structure of a library

     A Concept static library has 2 parts:

          •   The library events: ON_CREATE_CONTEXT and ON_DESTROY_CONTEXT
          •   The functions definition and implementation

     The Concept distribution provides a standard template for creating static libraries.

          -   stdlibrary.h – the Concept static library macros and definitions
          -   stdlibrary.cpp – for compatibility reasons between Windows and other *nix operating systems.

     Every static library developed for Concept MUST include stdlibrary.h , or its equivalents for other programming languages. The inclusion of stdlibrary.cpp in your project is pure optional but recommended if you intend to do the library fully portable.

     In the following section we'll discuss the library events.
     For now, Concept has only 2 library events: ON_CREATE_CONTEXT, called automatically by the concept machine when the library is loaded and ON_DESTROY_CONTEXT called on library unload (basically at the end of the execution of an application).
     This 2 function are used for "internal" memory management of a library. A practical example should be

#include "stdlibrary.h"

#define BUFFER_SIZE             8192
char    *some_internal_buffer   =   0;

// this function is called automatically when the library is loaded by the interpreter
CONCEPT_DLL_API ON_CREATE_CONTEXT MANAGEMENT_PARAMETERS {
    some_internal_buffer=new char[BUFFER_SIZE];
    
    // now, let's check if the allocation was successfully
    if (!some_internal_buffer)
        // if not, we'll return an error string, for the interpreter to show
        return (void *)"Can't allocate the internal buffer";
    return 0;
}

// ... internal functions //

// this function is called automatically when the application ends
CONCEPT_DLL_API ON_DESTROY_CONTEXT MANAGEMENT_PARAMETERS {
    delete[] some_internal_buffer;
    return 0;
}
     The example demonstrates the "internal memory management" of the library. The idea is that no programmer should manage the memory in Concept (due to the Smart Data Linking) and this principle should be applied to static libraries too when possible.

     If by any reason the ON_CREATE_CONTEXT function should fail, then should return a string with the error like in the upper example.


     Now, some things to do about a function:

          1.   A successfully function invocation returns 0 (null) (is a MUST)
          2.   If by any chance an error is encountered, the function should return a void pointer to a string containing the error text for the interpreter/machine to show to the programmer.
          3.   A static function is responsible for its memory allocation. A library should be clean, with no memory leaks
          4.   A static function should NEVER make delete or free on a Concept memory space.


The Invoker System

     The Invoker is a function received as a parameter to any function in the static library. All the functions in the library can call the Invoker, but the ON_CREATE_CONTEXT and ON_DESTROY_CONTEXT can use only one invoke parameter (INVOKE_DEFINE_CONSTANT).

     The invoke table
INVOKE_SET_VARIABLESets a variable type and valueUse
SET_STRING,
SET_BUFFER,
SET_NUMBER,
etc. instead (simpler)
INVOKE_GET_VARIABLEGets a variable type and valueUse GET_CHECK_STRING,
GET_CHECK_NUMBER,
GET_CHECK_BUFFER,
GET_CHECK_ARRAY,
etc. instead
INVOKE_SET_CLASS_MEMBERSets a value and type for a "variable" class member 
INVOKE_GET_CLASS_MEMBERGets a value and type for a "variable" class member 
INVOKE_GET_CLASS_VARIABLEGets a variable from a class as a handle 
INVOKE_FREE_VARIABLEFrees the memory allocated for a variable 
INVOKE_CREATE_ARRAYCreates an Array in the specified variable 
INVOKE_ARRAY_VARIABLEGets a handle to a variable from an array by index 
INVOKE_ARRAY_VARIABLE_BY_KEYGets a handle to a variable from an array by key 
INVOKE_GET_ARRAY_ELEMENTGets an array element by index 
INVOKE_SET_ARRAY_ELEMENTSets an array element by index 
INVOKE_GET_ARRAY_COUNTGets the array count 
INVOKE_GET_ARRAY_ELEMENT_BY_KEYGets an array element by key 
INVOKE_SET_ARRAY_ELEMENT_BY_KEYSets an array element by key 
INVOKE_CALL_DELEGATECalls a delegate (received as a parameter) 
INVOKE_COUNT_DELEGATE_PARAMSCounts the parameters of an delegate 
INVOKE_LOCK_VARIABLEIncrements the link-count for a variable. Use free variable for decrementing the links 
INVOKE_GET_ARRAY_KEYGets the key for the specified index of an array 
INVOKE_GET_ARRAY_INDEXGets the index for the specified key  
INVOKE_CREATE_VARIABLECrates a Concept variable 
INVOKE_DEFINE_CONSTANTDefines a Constant.This function can be called only from ON_CREATE_CONTEXT (before the program is actually executed)
INVOKE_SET_VARIABLE  [ top ]

Syntax: Invoke( 	INVOKE_SET_VARIABLE,
		void *variable_handler,
		INTEGER type,
		char *string_value,
		NUMBER number_value
	          );
Returns INVOKE_SUCCESS if operation ended successfully.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=0)
            return (void *)"foo: This function takes no parameters";

        if (!IS_OK(
           Invoke(INVOKE_SET_VARIABLE, RESULT, (INTEGER)VARIABLE_STRING, "Hello world !",(NUMBER)0)))
            return (void *)"foo: error setting the result";
        
        return 0;
}
You noticed here the IS_OK macro, which checks and return true if the Invoke function returns INVOKE_SUCCESS.

PARAMETERS_COUNT is the number of the parameters received by the function.
The cast form the last parameter (NUMBER)0 ensures that 0 is represented as a 64 bit double float number. The Invoke parameter list is variable, and for that you need to ensure that all the parameters have the required length.

For your commodity you have a simpler method that does the same thing:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you should 
        include this line in your function
        */
        LOCAL_INIT;

        if (PARAMETERS_COUNT!=0)
            return (void *)"foo: This function takes no parameters";

        RETURN_STRING("Hello World !");        
        return 0;
}
This example returns a string containing the "Hello World !!!" and is identical to the previous example.
Check the RETURN_STRING, SET_STRING, GET_NUMBER, etc. macros described in this guide.

INVOKE_GET_VARIABLE  [ top ]

Syntax: Invoke( 	INVOKE_SET_VARIABLE,
		void *variable_handler,
		INTEGER *type,
		char **string_value,
		NUMBER *number_value
	          );
Returns INVOKE_SUCCESS if operation ended successfully.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        INTEGER type;
        NUMBER nValue;
        char *szValue;


        if (!IS_OK(Invoke(INVOKE_GET_VARIABLE,PARAMETER(0), &type, &szValue, &nValue)))
            return (void *)"foo: error getting value";
        
        if (type!=VARIABLE_STRING)
            return (void *)"foo: parameter 0 should be a string";

        RETURN_STRING(szValue);
        return 0;
}
The same effect can be obtained using the GET_CHECK_STRING macro
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
        char *szValue;

        GET_CHECK_STRING(0,szValue,"foo: parameter 0 should be a string");

        RETURN_STRING(szValue);
        return 0;
}
GET_CHECK_* macros will be discussed later in this guide. First parameter of the GET_CHECK_STRING is the parameter order (0=first parameter), the second one is the container for the result, and the third one is the error returned if parameter 0 is not a string.

INVOKE_LOCK_VARIABLE & INVOKE_FREE_VARIABLE  [ top ]

Syntax: Invoke( 	INVOKE_LOCK_VARIABLE,
		void *variable_handler
	          );
	Invoke( 	INVOKE_FREE_VARIABLE,
		void *variable_handler
	          );
Returns INVOKE_SUCCESS if operation ended successfully.

Those 2 functions are presented together because they are somehow complementary.

INVOKE_LOCK_VARIABLE will increment the links for a variable while INVOKE_FREE_VARIABLE will decrement the links. If the links count become 0, the memory used by that variable will be freed.

Example:
void *HANDLER=0;

CONCEPT_DLL_API foo1 CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        if (!IS_OK(Invoke(INVOKE_LOCK_VARIABLE,PARAMETER(0))))
            return (void *)"foo1: error locking value";

        HANDLER=PARAMETER(0);

        // this function doesn't return any Concept value
        return 0;
}
//-------------------------------------------------------------------// 
CONCEPT_DLL_API foo2 CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=0)
            return (void *)"foo2: This function takes no parameters";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        (!IS_OK(Invoke(INVOKE_FREE_VARIABLE,HANDLER)))
            return (void *)"foo2: error freeing value";

        // this function doesn't return any Concept value
        return 0;
}
     This example will lock the PARAMETER(0) in the foo1. Concept comes with a "Garbage Collector" style mechanism called SDL (Smart Data Linking) and to ensure that the variable won't be freed up, you should lock the variable. Then, in foo2, when we don't need it anymore (we put in foo1 the handler of PARAMETER(0) in HANDLER) we can invoke the INVOKE_FREE_VARIABLE function to decrement the links and eventually to free up the memory used by that variable.

NOTE: Locking a variable and then never freeing it, will result in a memory leak.


INVOKE_CREATE_ARRAY  [ top ]

Syntax: Invoke( 	INVOKE_CREATE_ARRAY,
		void *variable_handler
	          );
Will change the type of the variable identified by variable_handler to array.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=0)
            return (void *)"foo: This function takes no parameters";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        // will create an array in the RESULT variable
        if (!IS_OK(Invoke(INVOKE_CREATE_ARRAY,RESULT)))
            return (void *)"foo: error creating array";

        return 0;
}
This will return to Concept an array.

INVOKE_GET_ARRAY_ELEMENT  [ top ]

Syntax: Invoke( 	INVOKE_GET_ARRAY_ELEMENT,
		void *variable_handler,
		INTEGER index,
		INTEGER *type,
		char **string_value,
		NUMBER *number_value
	          );
This function is similar to INVOKE_GET_VARIABLE except that will get the information from an array (by index)

Example:

CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS { if (PARAMETERS_COUNT!=1) return (void *)"foo: This function takes one parameter"; /* LOCAL_INIT initializes the local variables used by these macros. If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud include this line in your function */ LOCAL_INIT; void *arrayptr; GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array"); INTEGER index=0; INTEGER arr_type; INTEGER nArrValue; char *szArrValue; if (!IS_OK(Invoke(INVOKE_GET_ARRAY_ELEMENT, PARAMETER(0), index, &arr_type, &szArrValue, &nArrValue))) return (void *)"foo: error getting array element"; if (arr_type!=VARIABLE_STRING) return (void *)"foo: array element no. 0 should be a string"; RETURN_STRING(szArrValue); return 0; }

     This function will check using GET_CHECK_ARRAY macro if parameter 0 is an array; after that will try to get array element number 0 (index) and if is a string, will return that string.

INVOKE_GET_ARRAY_ELEMENT_BY_KEY  [ top ]

Syntax: Invoke( 	INVOKE_GET_ARRAY_ELEMENT,
		void *variable_handler,
		char *key,
		INTEGER *type,
		char **string_value,
		NUMBER *number_value
	          );
This function is similar to INVOKE_GET_VARIABLE except that will get the information from an array (by key)

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        char *key="a key";
        INTEGER arr_type;
        INTEGER nArrValue;
        char *szArrValue;

        if (!IS_OK(Invoke(INVOKE_GET_ARRAY_ELEMENT, PARAMETER(0), 
		    key, &arr_type, &szArrValue, &nArrValue)))
            return (void *)"foo: error getting array element";

        if (arr_type!=VARIABLE_STRING)
            return (void *)"foo: array element no. 0 should be a string";

        RETURN_STRING(szArrValue);
        return 0;
}
     This function will check using GET_CHECK_ARRAY macro if parameter 0 is an array; after that will try to get array element identified by key "a key" and if is a string, will return that string.

INVOKE_SET_ARRAY_ELEMENT  [ top ]

Syntax: Invoke( 	INVOKE_SET_ARRAY_ELEMENT,
		void *variable_handler,
		INTEGER index,
		INTEGER type,
		char *string_value,
		NUMBER number_value
	          );
This function is similar to INVOKE_SET_VARIABLE except that will get the information from an array (by index)

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        INTEGER index=0;
        INTEGER arr_type=TYPE_STRING;
        INTEGER nArrValue=0;
        char *szArrValue="Hello world !!";
        if (!IS_OK(Invoke(INVOKE_SET_ARRAY_ELEMENT, PARAMETER(0), 
		    index, arr_type, szArrValue, nArrValue)))
            return (void *)"foo: setting array";

        RETURN_NUMBER(0);
        return 0;
}
     This function will check using GET_CHECK_ARRAY macro if parameter 0 is an array; after that will try to set array element number 0 (index) to a string containing "Hello world !!". After that will return to Concept number 0 (see RETURN_NUMBER(0) ).

INVOKE_SET_ARRAY_ELEMENT_BY_KEY  [ top ]

Syntax: Invoke( 	INVOKE_SET_ARRAY_ELEMENT_BY_KEY,
		void *variable_handler,
		char *key,
		INTEGER type,
		char *string_value,
		NUMBER number_value
	          );
This function is similar to INVOKE_SET_VARIABLE except that will get the information from an array (by key)

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        char *key="a key";
        INTEGER arr_type=TYPE_STRING;
        INTEGER nArrValue=0;
        char *szArrValue="Hello world !!";

        if (!IS_OK(Invoke(INVOKE_SET_ARRAY_ELEMENT_BY_KEY, PARAMETER(0), 
            key, arr_type, szArrValue, nArrValue)))
            return (void *)"foo: setting array";

        RETURN_NUMBER(0);
        return 0;
}
     This function will check using GET_CHECK_ARRAY macro if parameter 0 is an array; after that will try to set array element identified by key "a key" to a string containing "Hello world !!". After that will return to Concept number 0 (see RETURN_NUMBER(0) ).

INVOKE_GET_VARIABLE  [ top ]

Syntax: Invoke( 	INVOKE_GET_VARIABLE,
		void *variable_handler,
		INTEGER index,
		void **element_handle
	          );
This function gets the handle to an element of an array.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        void *handle;
        INTEGER index=0;

        if (!IS_OK(Invoke(INVOKE_GET_VARIABLE, PARAMETER(0), index, &handle)))
            return (void *)"foo: error geting array variable";

        // now we have a handle to a variable member of an array

        RETURN_NUMBER(0);
        return 0;
}
     This example will get a handle to array [0]. When we have a handle to a variable, we can have direct access to this variable (faster). Let's say that we have an array member in an array, and then we need the second element from the array element. This can be done only using INVOKE_GET_VARIABLE twice or in conjunction with INVOKE_GET_ELEMENT or INVOKE_GET_ELEMENT_BY_KEY.

INVOKE_GET_VARIABLE_BY_KEY  [ top ]

Syntax: Invoke( 	INVOKE_GET_VARIABLE_BY_KEY,
		void *variable_handler,
		char *key,
		void **element_handle
	          );
This function gets the handle to an element of an array (by key).

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        void *handle;
        char *key="a key";

        if (!IS_OK(Invoke(INVOKE_GET_VARIABLE_BY_KEY,PARAMETER(0), key, &handle)))
            return (void *)"foo: error geting array variable";

        // now we have a handle to a variable member of an array

        RETURN_NUMBER(0);
        return 0;
}
     This example will get a handle to array ["a key"]. When we have a handle to a variable, we can have direct access to this variable (faster). Let's say that we have an array member in an array, and then we need the second element from the array element. This can be done only using INVOKE_GET_VARIABLE_BY_KEY twice or in conjunction with INVOKE_GET_ELEMENT or INVOKE_GET_ELEMENT_BY_KEY.

INVOKE_DEFINE_CONSTANT  [ top ]

Syntax: Invoke( 	INVOKE_DEFINE_CONSTANT,
		void *enviroment_handler,
		char *constant_name,
		char *constant_value
	          );
Define a constant in Concept from a static library.
NOTE: this function can be called only from ON_CREATE_CONTEXT. If it's called from a function, it has no effect.

Example:
CONCEPT_DLL_API ON_CREATE_CONTEXT MANAGEMENT_PARAMETERS {
	Invoke(INVOKE_DEFINE_CONSTANT, HANDLER, "SOME_CONSTANT", "10");
	return 0;
}
     This example defines a constant named SOME_CONSTANT and has a value of 10. The value can be anything. If is a string, don't forget to include the "" inside your string like this: Invoke(INVOKE_DEFINE_CONSTANT, HANDLER, "SOME_CONSTANT", "'some string'");
     You should now that Concept accepts both " and ' quotes. So "'some string'" is the same with "\"some string\"" in this second example. Don't forget in the ON_CREATE_CONTEXT to return 0 if no error is encountered. If you don't return 0, it means that an error was raised, and the library will not be loaded.

INVOKE_GET_ARRAY_COUNT  [ top ]

Syntax: Invoke( 	INVOKE_GET_ARRAY_COUNT,
		void *array
	          );
Get the count of an array (equivalent to Concept : length array).
Warning: this function returns the result as a run-code: exampled : result=Invoke(…)

Example
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        // returns the array count of parameter 0
        RETURN_NUMBER(Invoke(INVOKE_GET_ARRAY_COUNT,PARAMETER(0)));
        return 0;
}
Function "foo" returns the count of the array PARAMETER(0) as a number.

INVOKE_COUNT_DELEGATE_PARAMS  [ top ]

Syntax: Invoke( 	INVOKE_COUNT_DELEGATE_PARAMS,
		void *array
	          );
Returns the parameter-list count of a delegate function (a variable containing a reference to a function)
Warning: this function returns the result as a run-code: exampled : result=Invoke(…)

Example
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *dptr;
        INTEGER mptr;
        GET_CHECK_DELEGATE(0,dptr,mptr,"foo: parameter 0 should be a delegate");

        // returns the parameters count of delegate from parameters(0)
        RETURN_NUMBER(Invoke(INVOKE_COUNT_DELEGATE_PARAMS, PARAMETER(0)));
        return 0;
}
Function "foo" returns the count of the parameters in the function referenced by delegate PARAMETER(0) as a number.

INVOKE_GET_ARRAY_KEY  [ top ]

Syntax: Invoke( 	INVOKE_GET_ARRAY_KEY,
		void *array,
		INTEGER index,
		char **key
	          );
Return the key of the array element with an index specified by "index".

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        char *key=0;
        INTEGER index=0;
        if (!IS_OK(Invoke(INVOKE_GET_ARRAY_KEY,PARAMETER(0), index, &key)))
            return (void *)"foo: error getting key";

        RETURN_STRING(key);
        return 0;
}
The example above gets the key of the first element (specified by index=0) of an array and returns it to Concept.

INVOKE_GET_ARRAY_INDEX  [ top ]

Syntax: Invoke( 	INVOKE_GET_ARRAY_INDEX,
		void *array,
		char *key,
		INTEGER *index
	           );
Return the index of the array element with a key specified by "key".

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;
    
        void *arrayptr;
        GET_CHECK_ARRAY(0,arrayptr,"foo: parameter 0 should be an array");

        char *key="a key";
        INTEGER index=-1;
        if (!IS_OK(Invoke(INVOKE_GET_ARRAY_INDEX,PARAMETER(0), key, &index)))
            return (void *)"foo: error getting index";

        RETURN_NUMBER(index);
        return 0;
}
The example above gets the index of the array element that has "a key" as a key. If no element has that key, returns –1 in index.

INVOKE_CALL_DELEGATE  [ top ]

Syntax: Invoke( 	INVOKE_CALL_DELEGATE,
		void *delegate_handle,
		void **result_handle,
		void **exception_handle,
		INTEGER parameters_count,
		{ // for each parameter //
			INTEGER type,
			char *string_data,
			NUMBER number_data
		}
	          );
     Call a delegate and return the "return-data" in result_handle and if any exception is thrown, you'll find it in exception_handle. For each parameter (number of parameters is given by parameters_count) you must provide a triplet defined as (type, string_data, number_data) for each variable. (See INVOKE_SET_VARIABLE for details about the triplet).

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;

        NUMBER a_number=1001;
        char *a_string="Hello world !!!"
        void *RES=0;
        void *EXCEPTION=0;
    
        void *cls;
        NUMBER mid; 

        GET_CHECK_DELEGATE(0, cls, mid, "foo: parameter 0 should be a function delegate");

        Invoke(INVOKE_CALL_DELEGATE, PARAMETER(0), &RES, &EXCEPTION, (INTEGER)2, 
                  (INTEGER)VARIABLE_NUMBER, (char*)"", (double)a_number, 
                  (INTEGER)VARIABLE_STRING, a_string, (double)0);
        Invoke(INVOKE_FREE_VARIABLE,RES);
        Invoke(INVOKE_FREE_VARIABLE,EXCEPTION);

        RETURN_STRING(key);
        return 0;
}
     This example shows how to call a function delegate defined in Concept. First, we check if that function is a delegate (defined by classid <<cls>> and memberid <<mid>>). Then we call the delegate using RES as a container for the result, and EXCEPTION as a container for the exception. (INTEGER)2 is the number of parameters given to the delegate using triplets defined as (type, string_data, number_data) for each variable.

INVOKE_SET_CLASS_MEMBER  [ top ]

Syntax: Invoke( 	INVOKE_SET_CLASS_MEMBER,
		void *variable_handler,
		char *member_name,
		INTEGER type,
		char *string_value,
		NUMBER number_value
	          );
This function sets a member named member_name of an object identified by variable_handler. See INVOKE_SET_VARIABLE for more details.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;

        char *szValue="Hello world !";
        NUMBER nValue=0;
        INTEGER type=VARIABLE_STRING;

        if (!IS_OK(Invoke(INVOKE_SET_CLASS_MEMBER, PARAMETER(0), "member", type, szValue, nValue)))
            return "foo: error setting class member";

        RETURN_NUMBER(0);
        return 0;
}
     This function assumes that PARAMETER(0) is an instance of a class (an object) and has a member named "member". It sets its value to a string which contains "Hello world !".

INVOKE_GET_CLASS_MEMBER  [ top ]

Syntax: Invoke( 	INVOKE_GET_CLASS_MEMBER,
		void *variable_handler,
		char *member_name,
		INTEGER *type,
		char **string_value,
		NUMBER *number_value
	          );
This function gets a member named member_name of an object identified by variable_handler. See INVOKE_GET_VARIABLE for more details.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;

        char *szValue;
        NUMBER nValue;
        INTEGER type;

        if (!IS_OK(Invoke(INVOKE_GET_CLASS_MEMBER, PARAMETER(0), "member", &type, &szValue, &nValue)))
            return "foo: error getting class member";

        if (type!=VARIABLE_STRING)
            return "foo: member is not a string";

        RETURN_STRING(szValue);
        return 0;
}
     This function assumes that PARAMETER(0) is an instance of a class (an object) and has a member named "member". If "member" is a string, it returns its value. Otherwise it raises an error.

INVOKE_GET_CLASS_VARIABLE  [ top ]

Syntax: Invoke( 	INVOKE_GET_CLASS_VARIABLE,
		void *variable_handler,
		char *member_name,
		void *member_handler,
	          );
     This function gets the handle of a member named member_name of an object identified by variable_handler.

Example:
CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
        if (PARAMETERS_COUNT!=1)
            return (void *)"foo: This function takes one parameter";

        /*
        LOCAL_INIT initializes the local variables used by these macros. 
        If you intend to use macros such as RETURN_STRING or SET_NUMBER you shoud 
        include this line in your function
        */
        LOCAL_INIT;

        void *member_handle;

        if (!IS_OK(Invoke(INVOKE_GET_CLASS_VARIABLE, PARAMETER(0), "member", &member_handle)))
            return "foo: error getting class member";

        RETURN_NUMBER(0);
        return 0;
}
     This function assumes that PARAMETER(0) is an instance of a class (an object) and has a member named "member". Then it gets the handle of the member named "member".


The Concept Macros & Data types

     Concept mini DDK provides a set of macros designed to make development as easy as possible. Due to the difference of architecture between an Compiler and an Interpreter (Pseudo-compiler) it's a bit more abstract to define a static function for Concept.

The data types
INTEGER     is equivalent to C type int
POINTER     is equivalent to C type void *
NUMBER     is equivalent to C type double

Concept interpreter works only with NUMBER types and strings (char * in C).

Concept variable types are:
     -   VARIABLE_NUMBER
     -   VARIABLE_STRING
     -   VARIABLE_CLASS
     -   VARIABLE_ARRAY
     -   VARIABLE_DELEGATE

When reading a variable using the Invoker the variables are returned as it follows :
     -   VARIABLE_NUMBER: in string_data is "" or NULL, in number_data is the number
     -   VARIABLE_STRING: in string_data is the string, and in number_data is the length of that string
     -   VARIABLE_CLASS: in string_data(you should cast this one) is a pointer to a class handler, number_data is undefined.
     -   VARIABLE_ARRAY: in string_data(you should cast this one) is a pointer to an array handler, number_data is undefined.
     -   VARIABLE_DELEGATE: in string_data(you should cast this one) is a pointer to a class handler, in number_data is the member id of the delegate member

     FORWARD_CONCEPT_API_PARAMETERS is the list of the parameters for a concept library put in a form that you can call. If we have 2 functions and one of these must call the other one using the Concept "calling convention" (note the quotes: is not really a convention, but more like a set of parameters that should be validated).
     As an example, look below; the function foo is calling function foo1 that is a Concept-interfaced function. In the situation bellow you can say that function "foo" is an alias of function "foo1" (does the same thing, because it calls foo1 without doing anything else)

CONCEPT_DLL_API foo CONCEPT_API_PARAMETERS {
	foo1 FORWARD_CONCEPT_API_PARAMETERS
	return 0;
}
Let's see the macros (for examples you should check the previous section)

These macros :
CONCEPT_VA_LIST(LIST_NAME)
CONCEPT_VA_COPY(LIST_NAME1, LIST_NAME2)
CONCEPT_VA_START(LIST_NAME, index)
CONCEPT_VA_ARG(LIST_NAME, type)
CONCEPT_VA_END

     Are implemented for some kind of "syntax compatibility" with C allowing you to "walk" on parameters list using C style macros. This is a secondary method for getting Concept Parameters. The primary way is using the PARAMETER macros:

     E.g.: PARAMETER(0) will return a handle to the first parameter passed to the function; PARAMETER(1) the next one and so on. The result variable to return to Concept is found in RESULT.

     The count of the parameters is given by the macro PARAMETER_COUNT.

     Every function defined by you for Concept in a static library should have on the first line this :
          LOCAL_INIT;

     LOCAL_INIT defines all the variables needed by other macros such as GET_STRING.

     IS_OK(code) is a macro that checks if the Invoke function returns successfully or not (see the examples in the previous sections for more details)

     GET_STRING(param_index, szvariable) gets the param_index variable (0..PARAMETERS_COUNT) in szvariable (no special casting is necessary);

Example :
	char *param_0;
	GET_STRING(0,param0);
	or
	GET_CHECK_STRING(0,param0,"parameter 0 is not a string");
     GET_CHECK_STRING(param_index, szvariable, error_string) is the same as the GET_STRING but checks if the returned type is really a string or not. If it isn't it raises an error defined by you in error_string.

     GET_NUMBER(param_index, nvalue) is the similar to GET_STRING but the nvalue is a NUMBER in this case.
     GET_CHECK_NUMBER(parma_index,nvalue,error_string) gets a number and if selected parameter is not a number, raises an error defined in error_string.

     GET_BUFFER(param_index, szvariable, nlegth) gets a string or buffer, and its length in nlength. GET_CHECK_BUFFER(param_index, szvariable, nlegth, error_string) is the same with GET_BUFFER, except that performs a check for VARIABLE_STRING type. If it fails, raises an error as described to the similar functions above.

     GET_ARRAY(param_index, arrayptr) return the arrayptr for a index "param_index". Use GET_CHECK_ARRAY(param_index, arrayptr, error_string) to perform a type checking for TYPE_ARRAY.

     GET_DELEGATE(param_index, classptr, member_id) gets a delegate and described by classptr and member_id. To perform a check for type VARIABLE_DELEGATE use GET_CHECK_DELEGATE(param_index, classptr, member_id, error_string).

     Parameter checking macros:

PARAMETERS_CHECK(parameter_count,error_return)
     Checks the parameters count for EXACTLY 'parameter_count' parameters and if it does not match, raises an error described by a string in "error_return".

PARAMETERS_CHECK_MIN_MAX (pmin, pmax,error_return)
     Checks the parameters count for at least 'pmin' parameters and at most 'pmax' and if it does not match, raises an error described by a string in "error_return".

PARAMETERS_CHECK_MIN(pmin,error_return)
     Checks the parameters count for at least 'pmin' parameters and if it does not match, raises an error described by a string in "error_return".

© 2006 RadGs Software. All rights reserved.