Event handlers for the POS can be written in the C programming language. This is not required, but allows more possibilities for technical sites. C event handlers allow you to interface more easily to external systems, but allowing you to provide the glue logic.
The POS includes a small open source C compiler (TCC) which will dynamically compile and link your C code at runtime. Alternatively, you can precompile and ship a DLL/EXE with your functions.
Event Reference List. Documentation of each event code
The following event handler is called when a server system has processed and is about to store an inbound sale from a trading lane to the database. In this example, we simply log the sale details to a log file
:event(number(16100) index(0) lang(C)) #include <stdio.h> #include <share.h> FILE* pf = _fsopen("event16100.out", "a", _SH_DENYNO); if (pf) { long Sid = PosContext_GetField(pContext, 420); long Srcuid = PosContext_GetField(pContext, 400); long Locid = PosContext_GetField(pContext, 401); long Srcuidkey = PosContext_GetField(pContext, 421); fprintf(pf, "Sale Loaded Locid=%ld Srcuid=%ld sKey=%ld AsSid=%ld\n", Locid, Srcuid, Srcuidkey, Sid); fclose(pf); } return 0; :end
Allowing C into the POS processing has some guidelines that need to be followed. Your event handlers are operating in tightly controlled financially secure area
There are two ways C code can be implemented. As mini C routines inside Pos control files, or as true compiled and distributed code in a .DLL file
With mini C routines, you can place C code directly into event handlers. The POS will add required headers and entry points. This is essentially a short form of a full C compilation.
Each function called by the POS has the following function declaration
int FuncName(void* pContext);
The argument pContext is a pointer to an area of memory with full details of the call. A number of functions are provided which can extract the details from this structure. You should not modify the data pointed to be pContext it is intended to be Read-Only.
Mini C routines must return a valid return code. Routines that return invalid values may be subject to removal and not being called again
Value | Symbol | Description |
0 | FIELDPINE_REEV_NO_RESPONSE | I do not wish to affect the default outcome. Continue to call me in future. Use this code if you do not know what to respond with |
1 | FIELDPINE_REEV_ALLOW | Vote to specifically allow this operation |
2 | FIELDPINE_REEV_DENY | Vote to block or deny this operation |
4 | FIELDPINE_REEV_JUNCTION_DO_DEFAULT | For a Junction, this tells the system you explicitly want the default processing to occur. This is slightly different to NO_RESPONSE which says you do not care. Mostly this value is used where multiple event handlers are present on the same junction point. |
5 | FIELDPINE_REEV_JUNCTION_DONE | I have completed this operation and supplied a response. This code can only be used by Junction Events |
16 | FIELDPINE_REEV_REMOVE | Returns NO_RESPONSE internally but additionally marks that this handler does not need to be called again. This might be used by handlers that are not functional for some reason. Removed handlers are typically called again each time the Application starts, the removal is only for this process. |
17 | FIELDPINE_REEV_REMOVE_DATE | Same as REMOVE, but states that we are only being ignored for this processing date (complete 24 hour period). This response might be used by handlers that are only valid on certain days. |
The mini "C" interface is designed to be easy to write small scripts. It is not designed to handle very large programs, although it will work fine with larger programs
In order to simplify the scripts, there are a number of non-standard features used. You can disable these non standard features using the "entry()" directive (see below)
If needed, you can stop the system automatically adjusting and writing code by adding the directive entry().
:event(number(10002) index(0) lang(C) entry(MyFunc) ) int MyFunc(void* pContext) { // Process return 0; }
Defining the entry point can be useful if you need to create additional functions, for example
:event(number(10002) index(0) lang(C) entry(MyFunc) ) const char* GetMessage(int w) { if (w == 2) return "abc"; else return "def"; } int MyFunc(void* pContext) { const char* p = GetMessage(2); return 0; }
The mini "C" environment includes a number of API functions that are available. This allows you to read and write information to and from the PosEngine.
void PosCommand(const char*);
This function allows an event handler to request execution of a PosCommand. Event handlers should not cause recursion (ie cause the same event to be fired again while still active).
Select the item 2 before the one currently selected and then delete it from the sale
PosCommand("sale(sel-2)"); PosCommand("sale(delsel)");
void PosPrimitive(const char*);
long PosContext_GetField(void*, int);
long PosContext_GetFieldToBuffer(void*, int, void*, int);
char* PosContext_GetFieldPtr(void* pC, int Want, int* pOutLen);
long PosContext_SetFieldString(void* pC, int Want, const char*);
long PosContext_SetData(void* pC, const char*, const char*);
PosContext_SetData(pContext, "workingcommand.newscreen", "secret");
There are a number for functions specifically reserved for support and debugging. These functions must not be used to implement business logic and may be disabled, removed or changed without warning. They are intended to provide hooks for automatic support and analysis tools. Using these functions is an advanced option and not covered under operational support contracts
FLOW is used from the main engine to report what is happening inside. As the code moves through its execution it fires FLOW status reports. These can be trapped and handled by external functions for support purposes. Custom FLOW handlers can be used to capture additional error details for problem analysis, measure operation timing or as a debug PC like trace. Flow Reference
The following example causes the system to call the function "Flow88" whenever the code passes over the point numbered 88.
PosRegisterFlowHandler(88, 0, "Flow88", 0);