/**************************************************************************
 *{@C
 *      Copyright:      1988-2024 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         Utilities
 *      Filename:       UTT_TclIf.h
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    Declaration of general Tcl wrapper functions.
 *
 *      Additional documentation:
 *                      None.
 *
 **************************************************************************/

#ifndef __UTT_TCLIF_H__
#define __UTT_TCLIF_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <tcl.h>
#include "UT_Compat.h"

/* Check, if Tcl version supports Tcl_Size,
   which was introduced in Tcl 8.7 and 9.
*/
#ifndef TCL_SIZE_MAX
    #include <limits.h>
    #define TCL_SIZE_MAX INT_MAX

    #ifndef Tcl_Size
        typedef int Tcl_Size;
    #endif

    #define TCL_SIZE_MODIFIER ""
    #define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj
#endif

/* Definitions for the parameter lists needed by the Tcl wrapper functions. */

#define OBJPARAMLIST  \
        ClientData *clientData, Tcl_Interp *interp, int argc, char *argv[]
#define ELEMPARAMLIST \
        ClientData clientData,  Tcl_Interp *interp, int argc, char *argv[]
#define TCLPARAMLIST  \
        ClientData clientData,  Tcl_Interp *interp, int argc, char *argv[]

#define str_cant_read_param  "Cannot read actual parameter "

typedef struct {
    UT_Bool (*func)(OBJPARAMLIST);  /* C function which can be invoked
                                       through Tcl statements. */
    char *name;                     /* Name used to address the C
                                       function in Tcl statements. */
} UTT_TclObjFunc;

typedef struct {
    UT_Bool (*func)(ELEMPARAMLIST); /* C function which can be invoked
                                       through Tcl statements. */
    char *name;                     /* Name used to address the C
                                       function in Tcl statements. */
} UTT_TclElemFunc;

/* Note: The names "clientData", "argc" and "argv" are from the parameter
         list of the Tcl-interface routines. */

#define UTT_SetFalseResult                                              \
    {                                                                   \
        Tcl_SetResult (interp, "Error setting result", TCL_STATIC);     \
        return UT_False;                                                \
    }

#define UTT_ReturnFalse(n)                                              \
    {                                                                   \
        char paramInd[10];                                              \
        sprintf (paramInd, "%d", (n));                                  \
        /*Tcl_SetResult    (interp, str_cant_read_param, TCL_VOLATILE); */ \
        Tcl_AppendResult (interp, str_cant_read_param, (char *)NULL);   \
        Tcl_AppendResult (interp, paramInd, (char *) NULL);             \
        return UT_False;                                                \
    }

#define UTT_ObjHelp(str)                                                \
    {                                                                   \
        if (argc == 2 && argv[1][0] == '?') {                           \
            Tcl_SetResult (interp, (str), TCL_STATIC);                  \
            return TCL_OK;                                              \
        }                                                               \
    }

#define UTT_ParamHelp(str)                                              \
    {                                                                   \
        if (argc == 3 && argv[2][0] == '?') {                           \
            Tcl_SetResult (interp, (str), TCL_STATIC);                  \
            return UT_True;                                             \
        }                                                               \
    }

#define UTT_GetFixGeneric(tclfunc, n, var)                              \
    {                                                                   \
        if (((n) >= argc -1) ||                                         \
            ((tclfunc) (interp, argv[(n)+1], &(var)) != TCL_OK))        \
            UTT_ReturnFalse((n))                                        \
    }

#define UTT_GetOptGeneric(tclfunc, n, var, def)                         \
    {                                                                   \
        if ((n) >= argc -1)                                             \
            (var) = (def);                                              \
        else                                                            \
            UTT_GetFixGeneric ((tclfunc), (n), (var))                   \
    }

#define UTT_GetFixGenericList(tclfunc, n, var, nel, minlen)             \
    {                                                                   \
        if (((n) >= argc -1) ||                                         \
            ((tclfunc) (interp, argv[(n)+1], &(var), &(nel), (minlen)) != TCL_OK))        \
            UTT_ReturnFalse((n))                                        \
    }

#define UTT_GetOptGenericList(tclfunc, n, var, nel, minlen, def)        \
    {                                                                   \
        if ((n) >= argc -1)                                             \
        {                                                               \
            (var) = (def);                                              \
            (nel) = sizeof ((def)) / sizeof (*(def));                   \
        }                                                               \
        else                                                            \
            UTT_GetFixGenericList(tclfunc, n, var, nel, minlen) \
    }

#define UTT_SetFixGeneric(tclfunc, n, val)                            \
    {                                                                   \
        if (((n) >= argc -1) ||                                         \
            ((tclfunc) (interp, argv[(n)+1], (val)) != TCL_OK))         \
            UTT_ReturnFalse((n))                                       \
    }

#define UTT_SetOptGeneric(tclfunc, n, val)                            \
    {                                                                   \
        if ((n) < argc -1)                                              \
            UTT_SetFixGeneric ((tclfunc), (n), (val))                   \
    }

#define UTT_SetFixGenericResult(tclfunc, val)                        \
    {                                                                   \
        if ((tclfunc) (interp, (val)) != TCL_OK)                        \
            UTT_SetFalseResult                                          \
    }

#define UTT_SetFixGenericList(tclfunc, n, val, len)             \
    {                                                                   \
        if (((n) >= argc -1) ||                                         \
            ((tclfunc) (interp, argv[(n)+1], (val), (len)) != TCL_OK))  \
            UTT_ReturnFalse((n))                                       \
    }

#define UTT_GetFixBool(n, var)                                          \
    UTT_GetFixGeneric (UTT_GetBool, (n), (var))

#define UTT_GetOptBool(n, var, def)                                     \
    UTT_GetOptGeneric (UTT_GetBool, (n), (var), (def))

#define UTT_GetFixInt8(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetInt8, (n), (var))

#define UTT_GetOptInt8(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetInt8, (n), (var), (def))

#define UTT_GetFixUInt8(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetUInt8, (n), (var))

#define UTT_GetOptUInt8(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetUInt8, (n), (var), (def))

#define UTT_GetFixInt16(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetInt16, (n), (var))

#define UTT_GetOptInt16(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetInt16, (n), (var), (def))

#define UTT_GetFixUInt16(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetUInt16, (n), (var))

#define UTT_GetOptUInt16(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetUInt16, (n), (var), (def))

#define UTT_GetFixInt32(n, var)                                         \
    UTT_GetFixGeneric (Tcl_GetInt, (n), (var))

#define UTT_GetOptInt32(n, var, def)                                    \
    UTT_GetOptGeneric (Tcl_GetInt, (n), (var), (def))

#define UTT_GetFixUInt32(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetUInt32, (n), (var))

#define UTT_GetOptUInt32(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetUInt32, (n), (var), (def))

#define UTT_GetFixFloat32(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetFloat32, (n), (var))

#define UTT_GetOptFloat32(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetFloat32, (n), (var), (def))

#define UTT_GetFixFloat64(n, var)                                       \
    UTT_GetFixGeneric (UTT_GetFloat64, (n), (var))

#define UTT_GetOptFloat64(n, var, def)                                  \
    UTT_GetOptGeneric (UTT_GetFloat64, (n), (var), (def))

#define UTT_GetFixString(n, var, maxlen, pronly)                        \
    {                                                                   \
        if ((n) >= argc -1)                                             \
            UTT_ReturnFalse((n))                                        \
        strncpy ((var), argv[(n)+1], (maxlen));                         \
    }

#define UTT_GetFixFunct(n, var, maxlen)                                 \
    UTT_GetFixString (n, var, maxlen, UT_False)

#define UTT_GetOptString(n, var, maxlen, pronly, def)                   \
    {                                                                   \
        if ((n) >= argc -1)                                             \
            strncpy ((var), (def), (maxlen));                           \
        else                                                            \
            strncpy ((var), argv[(n)+1], (maxlen));                     \
    }

#define UTT_GetFixInt32List(n, var, nel, minlen)                        \
    UTT_GetFixGenericList(UTT_GetInt32List, n, var, nel, minlen)

#define UTT_GetOptInt32List(n, var, nel, minlen, def)                   \
    UTT_GetOptGenericList(UTT_GetInt32List, n, var, nel, minlen, def)

#define UTT_GetFixFloat32List(n, var, nel, minlen)                      \
    UTT_GetFixGenericList(UTT_GetFloat32List, n, var, nel, minlen)

#define UTT_GetOptFloat32List(n, var, nel, minlen, def)                 \
    UTT_GetOptGenericList(UTT_GetFloat32List, n, var, nel, minlen, def)

#define UTT_GetFixFloat64List(n, var, nel, minlen)                      \
    UTT_GetFixGenericList(UTT_GetFloat64List, n, var, nel, minlen)

#define UTT_GetOptFloat64List(n, var, nel, minlen, def)                 \
    UTT_GetOptGenericList(UTT_GetFloat64List, n, var, nel, minlen, def)

#define UTT_SetFixBool(n, val)                                          \
    UTT_SetFixGeneric (UTT_SetInt32, (n), (val))

#define UTT_SetOptBool(n, val)                                          \
    UTT_SetOptGeneric (UTT_SetInt32, (n), (val))

#define UTT_SetFixInt32(n, val)                                         \
    UTT_SetFixGeneric (UTT_SetInt32, (n), (val))

#define UTT_SetOptInt32(n, val)                                         \
    UTT_SetOptGeneric (UTT_SetInt32, (n), (val))

#define UTT_SetFixFloat32(n, val)                                       \
    UTT_SetFixGeneric (UTT_SetFloat32, (n), (val))

#define UTT_SetOptFloat32(n, val)                                       \
    UTT_SetOptGeneric (UTT_SetFloat32, (n), (val))

#define UTT_SetFixFloat64(n, val)                                       \
    UTT_SetFixGeneric (UTT_SetFloat64, (n), (val))

#define UTT_SetOptFloat64(n, val)                                       \
    UTT_SetOptGeneric (UTT_SetFloat64, (n), (val))

#define UTT_SetFixString(n, val)                                        \
    UTT_SetFixGeneric (UTT_SetString, (n), (val))

#define UTT_SetOptString(n, val)                                        \
    UTT_SetOptGeneric (UTT_SetString, (n), (val))

#define UTT_SetFixInt32Result(val)                                      \
    UTT_SetFixGenericResult(UTT_SetInt32Result, val)

#define UTT_SetFixFloat32Result(val)                                    \
    UTT_SetFixGenericResult(UTT_SetFloat32Result, val)

#define UTT_SetFixFloat64Result(val)                                    \
    UTT_SetFixGenericResult(UTT_SetFloat64Result, val)

#define UTT_SetFixStringResult(val)                                     \
    UTT_SetFixGenericResult(UTT_SetStringResult, val)

#define UTT_SetFixInt32List(n, val, len)                                \
    UTT_SetFixGenericList(UTT_SetInt32List, n, val, len)

#define UTT_SetFixFloat32List(n, val, len)                              \
    UTT_SetFixGenericList(UTT_SetFloat32List, n, val, len)

#define UTT_SetFixFloat64List(n, val, len)                              \
    UTT_SetFixGenericList(UTT_SetFloat64List, n, val, len)

typedef struct {
    Int32 value;      /* 32-bit integer value */
    char  *name;      /* Symbolic name for the value,
                         must be a string constant. */
} UTT_TclConstInt32;

typedef struct {
    Float64 value;    /* 64-bit float value */
    char    *name;    /* Symbolic name for the value,
                         must be a string constant. */
} UTT_TclConstFloat64;

extern POIMG_IMPORT_EXPORT int UTT_GetBool (Tcl_Interp *interp, CONST86 char *varName, UT_Bool *value);

extern POIMG_IMPORT_EXPORT int UTT_GetInt8  (Tcl_Interp *interp, CONST86 char *varName, Int8 *value);
extern POIMG_IMPORT_EXPORT int UTT_GetUInt8 (Tcl_Interp *interp, CONST86 char *varName, UInt8 *value);

extern POIMG_IMPORT_EXPORT int UTT_GetInt16  (Tcl_Interp *interp, CONST86 char *varName, Int16 *value);
extern POIMG_IMPORT_EXPORT int UTT_GetUInt16 (Tcl_Interp *interp, CONST86 char *varName, UInt16 *value);

/* Get an Int32 is handled with the standard Tcl Tcl_GetInt */
extern POIMG_IMPORT_EXPORT int UTT_GetUInt32 (Tcl_Interp *interp, CONST86 char *varName, UInt32 *value);

extern POIMG_IMPORT_EXPORT int UTT_GetFloat32 (Tcl_Interp *interp, CONST86 char *varName, Float32 *value);
extern POIMG_IMPORT_EXPORT int UTT_GetFloat64 (Tcl_Interp *interp, CONST86 char *varName, Float64 *value);

extern POIMG_IMPORT_EXPORT int UTT_SetInt32   (Tcl_Interp *interp, char *varName, int value);
extern POIMG_IMPORT_EXPORT int UTT_SetBool    (Tcl_Interp *interp, char *varName, UT_Bool value);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat32 (Tcl_Interp *interp, char *varName, Float32 value);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat64 (Tcl_Interp *interp, char *varName, Float64 value);
extern POIMG_IMPORT_EXPORT int UTT_SetString  (Tcl_Interp *interp, char *varName, char *value);

extern POIMG_IMPORT_EXPORT int UTT_SetInt32Result   (Tcl_Interp *interp, int value);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat32Result (Tcl_Interp *interp, Float32 value);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat64Result (Tcl_Interp *interp, Float64 value);
extern POIMG_IMPORT_EXPORT int UTT_SetStringResult  (Tcl_Interp *interp, char *value);

extern POIMG_IMPORT_EXPORT int UTT_GetInt32List   (Tcl_Interp *interp, char *varName, 
                               Int32 **var, Int32 *nel, Int32 minlen);
extern POIMG_IMPORT_EXPORT int UTT_GetFloat32List (Tcl_Interp *interp, char *varName,
                               Float32 **var, Int32 *nel, Int32 minlen);
extern POIMG_IMPORT_EXPORT int UTT_GetFloat64List (Tcl_Interp *interp, char *varName,
                               Float64 **var, Int32 *nel, Int32 minlen);

extern POIMG_IMPORT_EXPORT int UTT_SetInt32List   (Tcl_Interp *interp, char *varName, 
                               Int32 *val, Int32 len);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat32List (Tcl_Interp *interp, char *varName,
                               Float32 *val, Int32 len);
extern POIMG_IMPORT_EXPORT int UTT_SetFloat64List (Tcl_Interp *interp, char *varName,
                               Float64 *val, Int32 len);

extern POIMG_IMPORT_EXPORT UT_Bool     UTT_EvalFile  (Tcl_Interp *interp, const char *fname);
extern POIMG_IMPORT_EXPORT const char *UTT_GetResult (Tcl_Interp *interp);

extern POIMG_IMPORT_EXPORT int UTT_InitTclLib (Tcl_Interp *interp);

/* Functions declared in TCL_init.c */
extern POIMG_IMPORT_EXPORT int  UTT_TclInit (int argc, char *argv[], Tcl_AppInitProc *appInitProc);
extern POIMG_IMPORT_EXPORT void UTT_TclUpdate (int flags);
extern POIMG_IMPORT_EXPORT void UTT_TclClose (void);

#ifdef __cplusplus
}
#endif

#endif /* __UTT_TCLIF_H__ */
