/**
 * @file FCPE.h
 * @brief  FCPE - FLAM column processor exit
 * @author limes datentechnik gmbh
 * @date  07.08.2018
 * @copyright (c) 2018 limes datentechnik gmbh
 *
 * @mainpage FCPE - Service Provider Interface
 *
 * This service provider interface enables the possibility to write
 * custom pre- and post-processing exits for columns as part of
 * the table support in FLAM. It can be used to implement arbitrary
 * validation and transformation (e.g. tokenization, masking, encryption)
 * tasks based on data items of a column.
 *
 * The service provider interface can be invoked as one of the pre- or
 * post-processing steps for a column. See example below:
 *
 * <pre>
 * read.record(... table(... row(...
 * col(format.fix(...)
 *     process.exit(library='libfcpe', function='validate_string', parameter='format=IBAN')
 *     process.exit(library='libfcpe', function='mask_string', parameter='offset=4 length=6')
 *     process.exit(library='libfcpe', function='add_checksum', parameter='method=crc')
 *     type.string(...)
 * ))))
 * </pre>
 *
 * The different functions can have different parameter strings. All of them
 * depend on the implementation of the custom column processing exit according
 * to this service provider interface.
 *
 * @section IMPL Implementation overview
 * The interface that must be implemented to create a custom exit is
 * described in the @ref MAINFUNC "FCPE function" section. This interface
 * function must be an external function of a DLL/SO or load module (z/OS).
 * The (<code>PROCESS.EXIT()</code>) object is used to configure how to
 * call the custom exit routine.
 *
 * First, the DLL/SO is loaded based on the specified library name or
 * @ref DEFAULTNAMES "default name". Then the function address is
 * determined based on the provided function name or @ref DEFAULTNAMES "default name").
 * For load modules on z/OS, the function name is the load module name and
 * the library name must be empty. It is also possible to use DLLs on z/OS.
 *
 * If the @ref MAINFUNC "function pointer" is determined, the exit driver
 * calls the exit function with the function code for opening
 * (@ref FUNCCODE "see function codes"). A function-code-specific parameter
 * structure ((@ref FUNCSTRUCT "see FcpeOpn struct")) contains the parameter string
 * from the exit call specification (<code>PROCESS.EXIT(PARAMETER="xxx")</code>).
 * Additionally, a read or write indication flag and the table and column name are
 * provided as input. If the column processing is invertible, an inverse parameter
 * string can be returned by the exit implementation while opening which must be
 * suitable to configure the exit so that the changes made by this exit are reverted.
 * For text data, the CCSID (IBM - Coded Character Set Identifier) with the
 * combined character form ((@ref CMBFRM "see this section")) is provided as
 * 32 bit integer. If the character set is changed by the exit, then the CCSID
 * parameter must be adjusted by the exit.
 *
 * If the exit only performs validation tasks or updates the input data in-place,
 * then a flag bit must be set to indicate that the output buffer is not used
 * (@ref FCPEFALGS "see here").
 *
 * The first parameter of the exit function contains a handle. When it is
 * first called with the function code for opening (FCPE_FUNC_OPN), the
 * handle's value is NULL. This handle can be used to store state information
 * that may be needed during data processing by the exit (i.e. subsequent
 * calls with the FCPE_FUNC_RUN code). The exit function is responsible for
 * allocating memory for the handle (if needed) when called with the function
 * code for opening (FCPE_FUNC_OPN) and must release it (and all other
 * resources) when called with the function code for closing the exit
 * (FCPE_FUNC_CLS).
 *
 * When called with the run function code (FCPE_FUNC_RUN), the exit function
 * gets the input data length and a pointer to the input data as input
 * (see @ref FcpeRun) and writes the output data and its length to the respective
 * fields. If the exit function set the flag FCPE_FLAG_NOCPY during the opening
 * call to indicate that it does not write any data to the output buffer (e.g. the
 * data is only validated), the exit driver sets the output pointer to NULL
 * and expects that the exit pointer sets the output pointer to the input
 * pointer in the run function.
 *
 * Nonetheless, the exit function is called once more with the FCPE_FUNC_CLS
 * function code to allow the release of all resources.
 *
 * All function code specific parameter structures contain a length and
 * a buffer of size 1024 bytes for an error message. The error message is
 * displayed to the user if the return code differs from zero.
 *
 * @section ITFSTD Interface standards
 * The interface is built on one function with four parameters, a classic
 * load module interface. All parameters of the function are
 * call-by-reference. The function does not have a return value.
 * The return code is the second parameter of the function. There are only
 * two types of parameters:
 *
 * <pre>
 * POINTER:   pointer to an address (usually 32 (PIC S9(9) COMP) or 64 bit)
 * INTEGER:   pointer to a 32 bit number in two's complement (PIC S9(9) COMP)
 * </pre>
 *
 * The type INTEGER has local endianness. On mainframes, this is usually
 * big endian and little endian on x86 platforms.
 *
 * The POINTER type is used for the handle and the parameter structures.
 * The handle is a black box to FLAM. The parameter structures are unions
 * with the function code acting as selector
 * (@ref FUNCSTRUCT "see structures section").
 *
 * To support 64 bit RISC architectures, a strong alignment to 64 bit in the
 * parameter structures is required. This requires a 32 bit dummy field
 * behind each 32 bit length field. The trick with the dummy fields makes
 * the parameter structures compatible between the different supported
 * architectures of FLAM and prevents bus errors on certain platforms.
 *
 * All strings passed to the exit function are null-terminated and the
 * corresponding lengths are set to the string length in bytes without
 * the null character. The exit driver does not expect null-termination from
 * the exit function, but the length fields must be set correctly. For the
 * error message or the inverse string, the length can be set to the size
 * of the error message buffer (1024) or inverse string buffer, respectively,
 * if a null-terminated string is returned by the exit function.
 *
 * @section RTCH Return code handling
 * The return code of the function must be one of the defined FLAM return
 * codes (see module return codes). If the exit function is called
 * with the funtion code FCPE_FUNC_RUN, then FLMRTC_LEN must be returned
 * if the output buffer provided by the exit driver is too small to write
 * the result and set the output size to the minimum required buffer size.
 * If the input is not formatted correctly, FLMRTC_FMT must be returned to
 * support the format detection possibilities of FLAM. All other return codes
 * will result in an error and FLAM aborts the remaining processing.
 *
 * @section EXAMPLE Coding example for an FCPE
 * The example below uses the memory to memory interface to implement a simple
 * exit, where the from-to conversion string is used as parameter for
 * the service provider. The example is written in C and it implements
 * the three function codes as switch block.
 * The service provider interface specification (FCPE.h) and the FLUC byte
 * interface header (FLCBYT.h) must be included to implement the interface
 * and use the byte interface for conversion, respectively.
 * The @ref MAINFUNC "exit function" FCPETST implements the interface as
 * specified @ref MAINFUNC "here", using the FLUC memory to memory interface.
 *
 * <PRE>
 * \#include <stdio.h>
 *
 * \#include "FCPE.h"
 * \#include "FLCBYT.h"
 *
 * extern void FCPETST(
 *    void**         ppHdl,
 *    int*           piRetco,
 *    const int*     piFunc,
 *    TuFcpePar*     puPara)
 * {
 *    size_t         out;
 *    *piRetco=FLMRTC_OK;
 *    switch(*piFunc){
 *    case FCPE_FUNC_OPN:
 *       *ppHdl=fcbopenv(NULL,puPara->stOpn.pcPar);
 *       if(*ppHdl==NULL){
 *          *piRetco=fcberrno;
 *          snprintf(puPara->stOpn.acMsg,sizeof(puPara->stOpn.acMsg),"%s",fcberrtr());
 *          puPara->stOpn.uiMsg = strlen(puPara->stOpn.acMsg);
 *       }
 *       puPara->stOpn.uiIvr=0;
 *       puPara->stOpn.uiCcs=0;
 *       break;
 *    case FCPE_FUNC_RUN:
 *       out=puPara->stRun.uiOut;
 *       *piRetco=fcbconv(*ppHdl,puPara->stRun.uiInp,puPara->stRun.pcInp,&out,puPara->stRun.pcOut);
 *       puPara->stRun.uiOut=out;
 *       if(*piRetco){
 *          snprintf(puPara->stRun.acMsg,sizeof(puPara->stRun.acMsg),"%s",fcberrtr());
 *          puPara->stRun.uiMsg=strlen(puPara->stRun.acMsg);
 *       }
 *       break;
 *    case FCPE_FUNC_CLS:
 *       *piRetco = fcbclosev(*ppHdl);
 *       if(*piRetco){
 *          *piRetco=fcberrno;
 *          snprintf(puPara->stCls.acMsg,sizeof(puPara->stCls.acMsg),"%s",fcberrtr());
 *          puPara->stCls.uiMsg=strlen(puPara->stCls.acMsg);
 *       }
 *       break;
 *    default:
 *       *piRetco=FLMRTC_ITF;
 *       break;
 *    }
 * }
 * </PRE>
 *
 * For simplicity of the example, it the CCSID is set to zero and no
 * inverse string is returned. This simple implementation of the SPI is
 * quite powerful, because it provides the complete conversion functionality
 * of FLUC for each data item of a column.
 *
 * This test implementation is also deployed as sample C source (FCPETST.c)
 * in the installation package (SRCLIBC/samples). It can be used as role model
 * for other implementations.
 *
 * The implementation of an exit does not have to be done in C, but the binary
 * interface of the compiled and linked DLL/SO or load module must be compatible
 * to the C calling convention.
 *
 **********************************************************************/

/*! @cond PRIVATE */
#ifdef __cplusplus
   extern "C" {
#endif

#ifndef INC_FCPE_H
#define INC_FCPE_H
/*! @endcond */

/**********************************************************************/

#include"FLMRTC.h"
#include"FLMDEF.h"

/**********************************************************************/

/**
 * @defgroup FUNCCODE Function codes
 * @brief Function codes for column processing exit
 *
 * The function codes below are passed to the exit function by the exit driver
 * as the third parameter. It signals the current state to the exit function
 * which may act accordingly. The function code also defines the format of the
 * parameter structure. Only the union member of #TuFcpePar may be accessed
 * that matches the function code.
 * @{
 */
#define FCPE_FUNC_OPN      1 /**< @brief Function code for opening (used in the first call of the exit function) */
#define FCPE_FUNC_RUN      2 /**< @brief Function code for processing data      */
#define FCPE_FUNC_CLS      3 /**< @brief Function code for closing (used in the last call of the exit function) */
/**@}*/

/**
 * @defgroup DEFAULTNAMES Default names
 * @brief Default names used for library and function name
 *
 * The default names for the DLL/SO and the function name (load module
 * name) are used if no library name or function name are specified in the
 * <code>process.exit()</code> object.
 * @{
 */
#define FCPE_DEFLIB_NAME  "libfcpe" /**< @brief Default library name  */
#define FCPE_DEFFUC_NAME  "FLAMCPE" /**< @brief Default function name */
/**@}*/

/**
 * @defgroup CMBFRM Combined character forms
 * @brief Defines the combined character form
 *
 * The CCSID field in the parameter structure #TsFcpeOpn contains one of
 * these combined character forms (Unicode equivalence) in the 8 highest order bits.
 * If the form is not known then #FCPE_CMBFRM_NON should be used.
 * @{
 */
#define FCPE_CMBFRM_NON     0U /**< @brief No combined character form */
#define FCPE_CMBFRM_NFD     1U /**< @brief Normalization Form Canonical Decomposition */
#define FCPE_CMBFRM_NFC     2U /**< @brief Normalization Form Canonical Composition */
/**@}*/

 /**
  * @defgroup FCPEFALGS Flags for FCPE processing
  * @brief Definitions for the flag word in the parameter structure used for open
  *
  * In the open function the first word of the parameter structure contains
  * few bit settings.
  * @{
  */
 #define FCPE_FLAG_WRITE     0x00000001U /**< @brief [INPUT]  If set by exit driver, this signals that the exit is called as post-processing on the writing side */
 #define FCPE_FLAG_NOCPY     0x00000002U /**< @brief [OUTPUT] Must be set by the exit function if it does not write data to the output buffer (validation or in-place manipulation of input) */
 /**@}*/

/**********************************************************************/

/**
* @defgroup FUNCSTRUCT Function structures
* @brief Definition of the function code dependent structures for FCPE.
* @{
*/

/**
* @brief FCPE parameter structure for function code #FCPE_FUNC_OPN
*
* This structure is used when the exit function is called with the function
* code #FCPE_FUNC_OPN.
*
* The first member contains flags that can be set in both directions.
* If the exit is opened for converting output data, the flag bit #FCPE_FLAG_WRITE
* is set. If it is not set, the exit is opened for converting input data.
* The exit function may set the #FCPE_FLAG_NOCPY flag if it does not write
* to the output buffer in the #TsFcpeRun structure (i.e. it only validates
* or changes the data in-place).
*
* The second member contains the CCSID in the low order 24 bits. The
* high order 8 bits contain the @ref CMBFRM "combined character form".
* The member is set by the exit driver to a value corresponding to the
* input data and must be changed by the exit function only if its output
* is in a different character set. A CCSID of 0 indicates binary data.
* For example, if the exit function implements encryption of strings, the
* input text may be in UTF-8 (CCSID=1208). Since the encryption produces
* binary output, the CCSID must be set to 0.
*
* The next three member pairs contain the length and a pointer to the
* corresponding string with the table name, the column name and the
* parameter string. The parameter string must be interpreted by the
* service provider.
*
* The following member pair may be set by the exit function if the operation
* is invertible. The exit function must the pointer to the inverse
* parameter string and is responsible for allocating and freeing memory for
* this string. If the length is zero or the pointer is NULL, the exit is
* considered not invertible.
*
* The last member pair is a 1024 bytes buffer for an error message. The
* corresponding length must be set to the length of the error message.
*/
typedef struct FcpeOpn {
   /** @brief [INOUT] Flag word (32 bit) with several bit settings*/
   unsigned int         uiFlg;
   /** @brief [INOUT] CCSID in first low order 24 bit and the and combined character form in the high order 8 bit*/
   unsigned int         uiCcs;
   /** @brief [INPUT] Length of the table name (32 bit word)*/
   unsigned int         uiTab;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy1;
   /** @brief [INPUT] Pointer to the table name (32 or 64 bit)*/
   const char*          pcTab;
   /** @brief [INPUT] Length of the column name (32 bit word)*/
   unsigned int         uiCol;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy2;
   /** @brief [INPUT] Pointer to the column name (32 or 64 bit)*/
   const char*          pcCol;
   /** @brief [INPUT] Length of the parameter string (32 bit word)*/
   unsigned int         uiPar;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy3;
   /** @brief [INPUT] Pointer to the parameter string (32 or 64 bit)*/
   const char*          pcPar;
   /** @brief [OUTPUT] Length of the inverse parameter string (32 bit word)*/
   unsigned int         uiIvr;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy4;
   /** @brief [OUTPUT] Pointer to the inverse parameter string (32 or 64 bit)*/
   char*                pcIvr;
   /** @brief [OUTPUT] Length of error message (32 bit word)*/
   unsigned int         uiMsg;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy5;
   /** @brief [OUTPUT] Maximal 1024 byte long error string*/
   char                 acMsg[1024];
}TsFcpeOpn;

/**
* @brief FCPE Run structure
*
* This structure is used when the exit function is called with the function
* code #FCPE_FUNC_RUN. It is called for each data item of this column,
* allowing the exit to manipulate the data as needed.
*
* The exit drivers passes the length and a pointer to the input data of the
* current column as the first pair of members of the structure.
*
* The second member pair is the size and a pointer to an already allocated
* buffer where the exit function may write its output to and set the output
* length accordingly. The input and output buffers are managed by the exit
* driver. If the output buffer is too small, then FLMRTC_LEN must be set as
* return code and the output length must contain the minimum required buffer
* length. The exit driver then repeats the call with a buffer of at least the
* desired size. This is repeated until the exit function no longer sets
* the FLMRTC_LEN error code. If the @ref FCPEFALGS "FCPE_FLAG_NOCPY" flag
* is set, the output pointer and length is set to NULL/0 by the exit driver
* and the exit function must set the output length to the input length and
* the output pointer to the input pointer for plausibility checks by the
* exit driver.
*
* If the #FCPE_FLAG_NOCPY flag has been set during the FCPE_FUNC_RUN function
* code call, the input buffer may be modified in-place. However, the output
* pointer must be set to the input pointer. This prevents unnessary copy
* operation if the exit function only perform minor changes or none at all.
*
* The flag word can be used to set indication flags bits when reading and
* to use these flags when writing. Currently, the bit definitions below
* are defined:
*
*    FLMELM_TYPTAB_FLAG_NULLID
*    FLMELM_TYPTAB_FLAG_EMPTID
*
* At normal pre- or post-processing the flag word is not touched.
*
* The last member pair is a 1024 bytes buffer for an error message. The
* corresponding length must be set to the length of the error message.
*/
typedef struct FcpeRun {
   /** @brief [INPUT] Length of the input data (32 bit word)*/
   unsigned int         uiInp;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy1;
   /** @brief [INPUT] Pointer to the input data (32 or 64 bit)*/
   unsigned char*       pcInp;
   /** @brief [INOUT] Output space at input and output length at output (32 bit word)*/
   unsigned int         uiOut;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy2;
   /** @brief [OUTPUT] Pointer to the output data (32 or 64 bit)*/
   unsigned char*       pcOut;
   /** @brief [INOUT]  Flag word for null, empty and other indications (32 bit word) (output at read, input at write)*/
   unsigned int         uiFlg;
   /** @brief [OUTPUT] Length of error message (32 bit word)*/
   unsigned int         uiMsg;
   /** @brief [OUTPUT] Maximal 1024 byte long error string*/
   char                 acMsg[1024];
}TsFcpeRun;

/**
* @brief FCPE Close structure
*
* This structure is used when the exit function is called with the function
* code #FCPE_FUNC_CLS. It is always called after data processing is finished,
* no matter if there was error or not.
*
* The only member pair is a 1024 bytes buffer for an error message. The
* corresponding length must be set to the length of the error message.
*/
typedef struct FcpeCls {
   /** @brief [OUTPUT] Length of error message (32 bit word)*/
   unsigned int         uiMsg;
   /** @brief [DUMMY] 32 bit dummy field for 64 bit alignment*/
   unsigned int         uiDy1;
   /** @brief [OUTPUT] Maximal 1024 byte long error string*/
   char                 acMsg[1024];
}TsFcpeCls;

/**
* @brief FCPE Union of function structures
*
* This union must be used to access structure fields depending on the function
* code that was passed to exit function. Only the member that corresponds to
* the function code may be accessed. Failing to do so results in undefined behavior!
*/
typedef union FcpePar {
   /** @brief [INOUT] Structure for function code #FCPE_FUNC_OPN*/
   TsFcpeOpn            stOpn;
   /** @brief [INOUT] Structure for function code #FCPE_FUNC_RUN*/
   TsFcpeRun            stRun;
   /** @brief [INOUT] Structure for function code #FCPE_FUNC_CLS*/
   TsFcpeCls            stCls;
}TuFcpePar;
/**@}*/

/**********************************************************************/

/**
* @defgroup MAINFUNC FCPE function
* @brief This is the only function which must be provided by a DLL/SO or
* load module to fulfill the FLAM Column Processing Exit (FCPE) Service
* Provider Interface (SPI).
* @{
*/

/**
 * @brief FCPE function
 *
 * This is the function which must be implemented for user specific
 * column processing. The same handle is passed to consecutive calls and
 * may be used by the exit function to store internal state.
 *
 * The return code must be set as output parameter by the exit function.
 * The function code is an input parameter and contains one of the values
 * defined in @ref FUNCCODE "this section". Depending on the provided function
 * code, a pointer to a specific parameter structure is given as last parameter.
 *
 * @param [inout] ppHdl   POINTER Service provider handle
 * @param [out]   piRetco INTEGER Return code
 * @param [in]    piFunc  INTEGER Function code (OPN/RUN/CLS)
 * @param [inout] puPara  POINTER Parameter structure
 */
typedef void (TfFcpExit)(
   void**         ppHdl,
   int*           piRetco,
   const int*     piFunc,
   TuFcpePar*     puPara);
/**@}*/

/**********************************************************************/

/*! @cond PRIVATE */
#endif /* INC_FCPE_H */

#ifdef __cplusplus
   }
#endif
/*! @endcond */
