#ifndef _H_MACRO_
#define	_H_MACRO_

/** \ingroup rpmio
 * \file rpmmacro.h
 *
 * Macro API
 */

#include <stdio.h>
#include <stddef.h>

#include <rpm/rpmutil.h>
#include <rpm/rpmfileutil.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct rpmMacroEntry_s * rpmMacroEntry;

typedef struct rpmMacroContext_s * rpmMacroContext;

typedef struct rpmMacroBuf_s *rpmMacroBuf;

typedef void (*macroFunc)(rpmMacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parsed);

extern rpmMacroContext rpmGlobalMacroContext;

extern rpmMacroContext rpmCLIMacroContext;

/** \ingroup rpmrc
 * List of macro files to read when configuring rpm.
 * This is a colon separated list of files. URI's are permitted as well,
 * identified by the token '://', so file paths must not begin with '//'.
 */
extern const char * macrofiles;

/**
 * Markers for sources of macros added throughout rpm.
 */
#define	RMIL_BUILTIN	-20
#define	RMIL_DEFAULT	-15
#define	RMIL_MACROFILES	-13
#define	RMIL_RPMRC	-11

#define	RMIL_CMDLINE	-7
#define	RMIL_TARBALL	-5
#define	RMIL_SPEC	-3
#define	RMIL_OLDSPEC	-1
#define	RMIL_GLOBAL	0

/* Deprecated compatibility wrappers */
#define addMacro(_mc, _n, _o, _b, _l) rpmPushMacro(_mc, _n, _o, _b, _l)
#define delMacro(_mc, _n) rpmPopMacro(_mc, _n)

/* rpm expression parser flags */
#define RPMEXPR_EXPAND		(1 << 0)	/*!< expand primary terms */

/* rpm macro expansion flags */
#define RPMEXPAND_EXPAND_ARGS	(1 << 0)	/*!< expand arguments of parametric macros */
#define RPMEXPAND_KEEP_QUOTED	(1 << 1)	/*!< do not remove quotes from expanded macros */
#define RPMEXPAND_HAVE_QUOTED	(1 << 2)	/*!< expanded macros contain quote characters */

enum rpmMacroFlags_e {
    RPMMACRO_DEFAULT	= 0,
    RPMMACRO_LITERAL	= (1 << 0),		/*!< do not expand body of macro */
};
typedef rpmFlags rpmMacroFlags;

/** \ingroup rpmmacro
 * Print macros to file stream.
 * @param mc		macro context (NULL uses global context).
 * @param fp		file stream (NULL uses stderr).
 */
void	rpmDumpMacroTable	(rpmMacroContext mc,
					FILE * fp);

/** \ingroup rpmmacro
 * Expand macro into buffer.
 * @param mc		macro context (NULL uses global context).
 * @param sbuf		input macro to expand
 * @param obuf		macro expansion (malloc'ed)
 * @param flags		flags (currently unused)
 * @return		negative on failure
 */
int	rpmExpandMacros	(rpmMacroContext mc, const char * sbuf,
				char ** obuf, int flags);

/** \ingroup rpmmacro
 * Expand a specific macro into buffer.
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @param args		arguments for parametric macros
 * @param obuf		macro expansion (malloc'ed)
 * @param flags		flags (currently unused)
 * @return		negative on failure
 */
int	rpmExpandThisMacro (rpmMacroContext mc, const char *n,
				ARGV_const_t args,
				char ** obuf, int flags);

/** \ingroup rpmmacro
 * Push macro to context.
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @param o		macro parameters
 * @param b		macro body
 * @param level		macro recursion level (0 is entry API)
 * @return		0 on success
 */
int	rpmPushMacro	(rpmMacroContext mc, const char * n,
				const char * o,
				const char * b, int level);

/** \ingroup rpmmacro
 * Push macro to context.
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @param o		macro parameters
 * @param b		macro body
 * @param level		macro recursion level (0 is entry API)
 * @param flags		macro flags
 * @return		0 on success
 */
int	rpmPushMacroFlags	(rpmMacroContext mc, const char * n,
					const char * o,
					const char * b, int level,
					rpmMacroFlags flags);

/** \ingroup rpmmacro
 * Push an auxiliary macro to context.
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @param o		macro parameters (or NULL)
 * @param f		macro function
 * @param priv		private user data (or NULL)
 * @param nargs		number of arguments (0-N for enforced check,
 *			-1 for optional)
 * @param level		macro recursion level (0 is entry API)
 * @param flags		macro flags
 * @return		0 on success
 */
int rpmPushMacroAux(rpmMacroContext mc,
		    const char * n, const char * o,
		    macroFunc f, void *priv, int nargs,
		    int level, rpmMacroFlags flags);

/** \ingroup rpmmacro
 * Return macro entry user data (in aux macro)
 * @param me		macro entry
 * @return		pointer to private data passed on define or NULL
 */
void *rpmMacroEntryPriv(rpmMacroEntry me);

/** \ingroup rpmmacro
 * Append a character to macro buffer (in aux macro)
 * @param mb		macro buffer
 * @param c		character to append
 */
void rpmMacroBufAppend(rpmMacroBuf mb, char c);

/** \ingroup rpmmacro
 * Append a string to macro buffer (in aux macro)
 * @param mb		macro buffer
 * @param str		string to append
 */
void rpmMacroBufAppendStr(rpmMacroBuf mb, const char *str);

/** \ingroup rpmmacro
 * Raise an error or warning in macro buffer (in aux macro)
 * @param mb		macro buffer
 * @param error		1 if error, 0 if warning
 * @param fmt		j
 */
RPM_GNUC_PRINTF(3, 4)
void rpmMacroBufErr(rpmMacroBuf mb, int error, const char *fmt, ...);

/** \ingroup rpmmacro
 * Pop macro from context.
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @return		0 on success
 */
int	rpmPopMacro	(rpmMacroContext mc, const char * n);

/** \ingroup rpmmacro
 * Define macro in context.
 * @param mc		macro context (NULL uses global context).
 * @param macro		macro name, options, body
 * @param level		macro recursion level (0 is entry API)
 * @return		0 on success (always)
 */
int	rpmDefineMacro	(rpmMacroContext mc, const char * macro,
				int level);

/**
 * Test whether a macro is defined
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @return		1 if defined, 0 if not
 */
int rpmMacroIsDefined(rpmMacroContext mc, const char *n);

/**
 * Test whether a macro is parametric (ie takes arguments)
 * @param mc		macro context (NULL uses global context).
 * @param n		macro name
 * @return		1 if parametric, 0 if not
 */
int rpmMacroIsParametric(rpmMacroContext mc, const char *n);

/** \ingroup rpmmacro
 * Load macros from specific context into global context.
 * @param mc		macro context (NULL does nothing).
 * @param level		macro recursion level (0 is entry API)
 */
void	rpmLoadMacros	(rpmMacroContext mc, int level);

/** \ingroup rpmmacro
 * Load macro context from a macro file.
 * @param mc		(unused)
 * @param fn		macro file name
 */
int	rpmLoadMacroFile(rpmMacroContext mc, const char * fn);

/** \ingroup rpmmacro
 * Initialize macro context from set of macrofile(s).
 * @param mc		macro context
 * @param macrofiles	colon separated list of macro files (NULL does nothing)
 */
void	rpmInitMacros	(rpmMacroContext mc, const char * macrofiles);

/** \ingroup rpmmacro
 * Destroy macro context.
 * @param mc		macro context (NULL uses global context).
 */
void	rpmFreeMacros	(rpmMacroContext mc);

/** \ingroup rpmmacro
 * Return (malloc'ed) concatenated macro expansion(s).
 * @param arg		macro(s) to expand (NULL terminates list)
 * @return		macro expansion (malloc'ed)
 */
char * rpmExpand	(const char * arg, ...) RPM_GNUC_NULL_TERMINATED;

/** \ingroup rpmmacro
 * Return macro expansion as a numeric value.
 * Boolean values ('Y' or 'y' returns 1, 'N' or 'n' returns 0)
 * are permitted as well. An undefined macro returns 0.
 * @param arg		macro to expand
 * @return		numeric value
 */
int	rpmExpandNumeric (const char * arg);

/** \ingroup rpmmacro
 * Return rpm configuration base directory.
 * If RPM_CONFIGDIR environment variable is set, it's value will be used.
 * Otherwise the configuration directory is the one set at build time,
 * typically /usr/lib/rpm. The value of rpmConfigDir() is determined
 * on first call to this function and is guaranteed to remain the same
 * on subsequent calls.
 * @return		rpm configuration directory name
 */
const char *rpmConfigDir(void);

/** \ingroup rpmmacro
 * Evaluate boolean expression.
 * @param expr		expression to parse
 * @param flags		parser flags
 * @return
 */
int rpmExprBoolFlags(const char * expr, int flags);

/** \ingroup rpmmacro
 * Evaluate string expression.
 * @param expr		expression to parse
 * @param flags		parser flags
 * @return
 */
char * rpmExprStrFlags(const char * expr, int flags);

/** \ingroup rpmmacro
 * Evaluate boolean expression.
 * @param expr		expression to parse
 * @return
 */
int rpmExprBool(const char * expr);

/** \ingroup rpmmacro
 * Evaluate string expression.
 * @param expr		expression to parse
 * @return
 */
char * rpmExprStr(const char * expr);

#ifdef __cplusplus
}
#endif

#endif	/* _H_ MACRO_ */
