/* rsyslog rainerscript definitions
 *
 * Copyright 2011-2025 Rainer Gerhards
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *       -or-
 *       see COPYING.ASL20 in the source distribution
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef INC_UTILS_H
#define INC_UTILS_H
#include <stdio.h>
#include <libestr.h>
#include <typedefs.h>
#include <sys/types.h>
#include <json.h>
#include <regex.h>
#include "typedefs.h"

#undef LOG_NFACILITIES
#define LOG_NFACILITIES 24 + 1 /* we copy&paste this as including rsyslog.h gets us in off64_t trouble... :-( */
#define CNFFUNC_MAX_ARGS 32
/**< maximum number of arguments that any function can have (among
 *   others, this is used to size data structures).
 */

enum cnfobjType {
    CNFOBJ_ACTION,
    CNFOBJ_RULESET,
    CNFOBJ_GLOBAL,
    CNFOBJ_INPUT,
    CNFOBJ_MODULE,
    CNFOBJ_TPL,
    CNFOBJ_PROPERTY,
    CNFOBJ_CONSTANT,
    CNFOBJ_MAINQ,
    CNFOBJ_LOOKUP_TABLE,
    CNFOBJ_PARSER,
    CNFOBJ_TIMEZONE,
    CNFOBJ_DYN_STATS,
    CNFOBJ_PERCTILE_STATS,
    CNFOBJ_INVALID = 0
};

const char *cnfobjType2str(enum cnfobjType ot);

/* a variant type, for example used for expression evaluation
 * 2011-07-15/rger: note that there exists a "legacy" object var,
 * which implements the same idea, but in a suboptimal manner. I have
 * stipped this down as much as possible, but will keep it for a while
 * to avoid unnecessary complexity during development. TODO: in the long
 * term, var shall be replaced by struct svar.
 */
struct svar {
    union {
        es_str_t *estr;
        struct cnfarray *ar;
        long long n;
        struct json_object *json;
    } d;
    char datatype; /* 'N' number, 'S' string, 'J' JSON, 'A' array
                    * Note: 'A' is only supported during config phase
                    */
};

struct cnfobj {
    enum cnfobjType objType;
    struct nvlst *nvlst;
    struct objlst *subobjs;
    struct cnfstmt *script;
};

struct objlst {
    struct objlst *next;
    struct cnfobj *obj;
};

struct nvlst {
    struct nvlst *next;
    es_str_t *name;
    struct svar val;
    unsigned char bUsed;
    /**< was this node used during config processing? If not, this
     *   indicates an error. After all, the user specified a setting
     *   that the software does not know.
     */
};

/* the following structures support expressions, and may (very much later
 * be the sole foundation for the AST.
 *
 * nodetypes (list not yet complete)
 * A - (string) array
 * F - function
 * N - number
 * P - fparamlst
 * R - rule
 * S - string
 * V - var
 * ... plus the S_* #define's below:
 */
#define S_STOP 4000
#define S_PRIFILT 4001
#define S_PROPFILT 4002
#define S_IF 4003
#define S_ACT 4004
#define S_NOP 4005 /* usually used to disable some statement */
#define S_SET 4006
#define S_UNSET 4007
#define S_CALL 4008
#define S_FOREACH 4009
#define S_RELOAD_LOOKUP_TABLE 4010
#define S_CALL_INDIRECT 4011
#define S_FUNC_EXISTS 4012 /* special case function which must get varname only */

enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT };
const char *cnfFiltType2str(const enum cnfFiltType filttype);


struct cnfstmt {
    unsigned nodetype;
    struct cnfstmt *next;
    uchar *printable; /* printable text for debugging */
    union {
        struct {
            struct cnfexpr *expr;
            struct cnfstmt *t_then;
            struct cnfstmt *t_else;
        } s_if;
        struct {
            uchar *varname;
            struct cnfexpr *expr;
            int force_reset;
        } s_set;
        struct {
            uchar *varname;
        } s_unset;
        struct {
            es_str_t *name;
            struct cnfstmt *stmt;
            ruleset_t *ruleset; /* non-NULL if the ruleset has a queue assigned */
        } s_call;
        struct {
            struct cnfexpr *expr;
        } s_call_ind;
        struct {
            uchar pmask[LOG_NFACILITIES + 1]; /* priority mask */
            struct cnfstmt *t_then;
            struct cnfstmt *t_else;
        } s_prifilt;
        struct {
            fiop_t operation;
            regex_t *regex_cache; /* cache for compiled REs, if used */
            struct cstr_s *pCSCompValue; /* value to "compare" against */
            sbool isNegated;
            msgPropDescr_t prop; /* requested property */
            struct cnfstmt *t_then;
            struct cnfstmt *t_else;
        } s_propfilt;
        struct action_s *act;
        struct {
            struct cnfitr *iter;
            struct cnfstmt *body;
        } s_foreach;
        struct {
            lookup_ref_t *table;
            uchar *table_name;
            uchar *stub_value;
        } s_reload_lookup_table;
    } d;
};

struct cnfexpr {
    unsigned nodetype;
    struct cnfexpr *l;
    struct cnfexpr *r;
} __attribute__((aligned(8)));

struct cnfitr {
    char *var;
    struct cnfexpr *collection;
} __attribute__((aligned(8)));

struct cnfnumval {
    unsigned nodetype;
    long long val;
} __attribute__((aligned(8)));

struct cnfstringval {
    unsigned nodetype;
    es_str_t *estr;
} __attribute__((aligned(8)));

struct cnfvar {
    unsigned nodetype;
    char *name;
    msgPropDescr_t prop;
} __attribute__((aligned(8)));

struct cnfarray {
    unsigned nodetype;
    int nmemb;
    es_str_t **arr;
} __attribute__((aligned(8)));

struct cnffparamlst {
    unsigned nodetype; /* P */
    struct cnffparamlst *next;
    struct cnfexpr *expr;
} __attribute__((aligned(8)));

enum cnffuncid {
    CNFFUNC_INVALID = 0, /**< defunct entry, do not use (should normally not be present) */
    CNFFUNC_NAME = 1, /**< use name to call function (for future use) */
    CNFFUNC_STRLEN,
    CNFFUNC_SUBSTRING,
    CNFFUNC_GETENV,
    CNFFUNC_TOLOWER,
    CNFFUNC_CSTR,
    CNFFUNC_CNUM,
    CNFFUNC_RE_MATCH,
    CNFFUNC_RE_EXTRACT,
    CNFFUNC_FIELD,
    CNFFUNC_PRIFILT,
    CNFFUNC_LOOKUP,
    CNFFUNC_EXEC_TEMPLATE,
    CNFFUNC_REPLACE,
    CNFFUNC_WRAP,
    CNFFUNC_RANDOM,
    CNFFUNC_DYN_INC,
    CNFFUNC_IPV42NUM,
    CNFFUNC_NUM2IPV4,
    CNFFUNC_INT2HEX,
    CNFFUNC_LTRIM,
    CNFFUNC_RTRIM,
    CNFFUNC_FORMAT_TIME,
    CNFFUNC_PARSE_TIME,
    CNFFUNC_PARSE_JSON,
    CNFFUNC_GET_PROPERTY,
    CNFFUNC_PREVIOUS_ACTION_SUSPENDED,
    CNFFUNC_SCRIPT_ERROR,
    CNFFUNC_HTTP_REQUEST,
    CNFFUNC_IS_TIME
};

typedef struct cnffunc cnffunc_t;
typedef void (*rscriptFuncPtr)(cnffunc_t *, struct svar *, void *, wti_t *);

struct cnffunc {
    unsigned nodetype;
    es_str_t *fname;
    unsigned short nParams;
    rscriptFuncPtr fPtr;
    void *funcdata; /* global data for function-specific use (e.g. compiled regex) */
    uint8_t destructable_funcdata;
    struct cnfexpr *expr[];
} __attribute__((aligned(8)));


struct cnffuncexists {
    unsigned nodetype;
    const char *varname;
    msgPropDescr_t prop;
} __attribute__((aligned(8)));

struct scriptFunct {
    const char *fname;
    unsigned short minParams;
    unsigned short maxParams;
    rscriptFuncPtr fPtr;
    rsRetVal (*initFunc)(struct cnffunc *);
    void (*destruct)(struct cnffunc *);
    /* currently no optimizer entrypoint, may be added later.
     * Since the optimizer needs metadata about functions, it does
     * not seem practical to add such a function at the current state
     */
};


/* future extensions
<code>
struct x {
    int nodetype;
};
</code>
*/


/* the following defines describe the parameter block used to describe
 * configuration parameters.
 *
 * All modules use this parameter block to describe their parameters.
 * There are two classes of parameter blocks implemented by the same
 * structure:
 *
 * - module paramters
 *   - configure the module itself
 *   - set defaults
 *   - configure module operation modes, if that mode can only
 *     be used for all its instances (e.g. actions, inputs)
 *   - modules which by function cannot have several instances may
 *     configure instance-type parameters via module parameters
 *   - some older modules also intermix module and instance parameters
 *   - modules should support setting default values via module parameters
 *   - if not set, the parameter defaults to hardcoded value
 *   - the variable has a fixed name inside the code and is defined
 *     as follows: struct cnfparamblk modpblk
 *
 * - instance parameter
 *   - provide config for the instance, e.g. an input or action
 *   - if not set, defaults to module default parameter
 *   - the variable has a fixed name inside the code and is defined
 *     as follows: struct cnfparamblk <type-prefix>pblk, with <type-perefix>
 *     - important uses (name: config statement it is used for)
 *     - inppblk: input()
 *     - actpblk: action()
 *     - parserpblk: parser()
 *     - some few definitions are different for historical or technical reasons
 *
 * Implementation Note: the focus of algorithms using  this block is
 * - simple, robust code
 * - secure code
 * - performance is uncritical, as only used during startup phase
 *
 * For example, we address parameters by name
 * instead of index, because the former is less error-prone. The (severe)
 * performance hit does not matter, as it is a one-time hit during config
 * load but never during actual processing. So there is really no reason
 * to care.
 */
struct cnfparamdescr { /* first the param description */
    const char *name; /**< configuration parameter name, e.g. "port" */
    ecslCmdHdrlType type; /**< parameter type as defined by  enum cslCmdHdlrType */
    unsigned flags; /**< flags describing important properties, e.g. if optional or mandatory */
};
/* flags for cnfparamdescr. if no flag is given parameter is optional.*/
#define CNFPARAM_REQUIRED 0x0001 /**< signifies a mandatory parameter */
#define CNFPARAM_DEPRECATED 0x0002 /**< signifies a deprecated parameter */

struct cnfparamblk { /* now the actual param block use in API calls */
    unsigned short version;
    unsigned short nParams;
    struct cnfparamdescr *descr;
};
#define CNFPARAMBLK_VERSION 1
/**< caller must have same version as engine -- else things may
 * be messed up. But note that we may support multiple versions
 * inside the engine, if at some later stage we want to do
 * that. -- rgerhards, 2011-07-15
 */
struct cnfparamvals { /* the values we obtained for param descr. */
    struct svar val;
    unsigned char bUsed;
};

struct funcData_prifilt {
    uchar pmask[LOG_NFACILITIES + 1]; /* priority mask */
};

/* script errno-like interface error codes: */
#define RS_SCRIPT_EOK 0
#define RS_SCRIPT_EINVAL 1

void varFreeMembers(const struct svar *r);
rsRetVal addMod2List(const int version, struct scriptFunct *functArray);
void readConfFile(FILE *fp, es_str_t **str);
struct objlst *objlstNew(struct cnfobj *obj);
void objlstDestruct(struct objlst *lst);
void objlstPrint(struct objlst *lst);
struct nvlst *nvlstNewArray(struct cnfarray *ar);
struct nvlst *nvlstNewStr(es_str_t *value);
struct nvlst *nvlstNewStrBackticks(es_str_t *const value);
struct nvlst *nvlstSetName(struct nvlst *lst, es_str_t *name);
void nvlstDestruct(struct nvlst *lst);
void nvlstPrint(struct nvlst *lst);
void nvlstChkUnused(struct nvlst *lst);
struct nvlst *nvlstFindName(struct nvlst *lst, es_str_t *name);
int nvlstChkDisabled(struct nvlst *lst);
struct cnfobj *cnfobjNew(enum cnfobjType objType, struct nvlst *lst);
void cnfobjDestruct(struct cnfobj *o);
void cnfobjPrint(struct cnfobj *o);
struct cnfexpr *cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r);
void cnfexprPrint(struct cnfexpr *expr, int indent);
void cnfexprEval(const struct cnfexpr *const expr, struct svar *ret, void *pusr, wti_t *pWti);
int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr, wti_t *pWti);
struct json_object *cnfexprEvalCollection(struct cnfexpr *const expr, void *const usrptr, wti_t *pWti);
void cnfexprDestruct(struct cnfexpr *expr);
struct cnfnumval *cnfnumvalNew(long long val);
struct cnfstringval *cnfstringvalNew(es_str_t *estr);
struct cnfvar *cnfvarNew(char *name);
struct cnffunc *cnffuncNew(es_str_t *fname, struct cnffparamlst *paramlst);
struct cnffuncexists *cnffuncexistsNew(const char *varname);
struct cnffparamlst *cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next);
int cnfDoInclude(const char *name, const int optional);
int cnfparamGetIdx(struct cnfparamblk *params, const char *name);
struct cnfparamvals *nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, struct cnfparamvals *vals);
void cnfparamsPrint(const struct cnfparamblk *params, const struct cnfparamvals *vals);
int cnfparamvalsIsSet(struct cnfparamblk *params, struct cnfparamvals *vals);
void varDelete(const struct svar *v);
void cnfparamvalsDestruct(const struct cnfparamvals *paramvals, const struct cnfparamblk *blk);
struct cnfstmt *cnfstmtNew(unsigned s_type);
struct cnfitr *cnfNewIterator(char *var, struct cnfexpr *collection);
void cnfstmtPrintOnly(struct cnfstmt *stmt, int indent, sbool subtree);
void cnfstmtPrint(struct cnfstmt *stmt, int indent);
struct cnfstmt *scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s);
struct objlst *objlstAdd(struct objlst *root, struct cnfobj *o);
char *rmLeadingSpace(char *s);
struct cnfstmt *cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then);
struct cnfstmt *cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then);
struct cnfstmt *cnfstmtNewAct(struct nvlst *lst);
struct cnfstmt *cnfstmtNewLegaAct(char *actline);
struct cnfstmt *cnfstmtNewSet(char *var, struct cnfexpr *expr, int force_reset);
struct cnfstmt *cnfstmtNewUnset(char *var);
struct cnfstmt *cnfstmtNewCall(es_str_t *name);
struct cnfstmt *cnfstmtNewContinue(void);
struct cnfstmt *cnfstmtNewReloadLookupTable(struct cnffparamlst *fparams);
void cnfstmtDestructLst(struct cnfstmt *root);
struct cnfstmt *cnfstmtOptimize(struct cnfstmt *root);
struct cnfarray *cnfarrayNew(es_str_t *val);
struct cnfarray *cnfarrayDup(struct cnfarray *old);
struct cnfarray *cnfarrayAdd(struct cnfarray *ar, es_str_t *val);
void cnfarrayContentDestruct(struct cnfarray *ar);
const char *getFIOPName(unsigned iFIOP);
rsRetVal initRainerscript(void);
void unescapeStr(uchar *s, int len);
const char *tokenval2str(int tok);
uchar *var2CString(struct svar *__restrict__ const r, int *__restrict__ const bMustFree);
long long var2Number(struct svar *r, int *bSuccess);
void includeProcessCnf(struct nvlst *const lst);

/* debug helper */
void cstrPrint(const char *text, es_str_t *estr);

#endif
