/* fmt_scan.h -- definitions for fmt_scan()
 */

/*
 * This structure describes an "interesting" component.  It holds
 * the name & text from the component (if found) and one piece of
 * auxiliary info.  The structure for a particular component is located
 * by (open) hashing the name and using it as an index into the ptr array
 * "wantcomp".  All format entries that reference a particular component
 * point to its comp struct (so we only have to do component specific
 * processing once.  e.g., parse an address.).
 *
 * In previous implementations "wantcomp" was made available to other
 * functions, but now it's private and is accessed via functions.
 */
struct comp {
    char        *c_name;	/* component name (in lower case) */
    char        *c_text;	/* component text (if found)      */
    struct comp *c_next;	/* hash chain linkage             */
    short        c_flags;	/* misc. flags (from fmt_scan)    */
    short        c_type;	/* type info   (from fmt_compile) */
    union {
	struct tws *c_u_tws;
	struct mailname *c_u_mn;
    } c_un;
    int          c_refcount;	/* Reference count                */
};

#define c_tws c_un.c_u_tws
#define c_mn  c_un.c_u_mn

/*
 * c_type bits
 */
#define	CT_ADDR       (1<<0)	/* referenced as address    */
#define	CT_DATE       (1<<1)	/* referenced as date       */

#define CT_BITS       "\020\01ADDR\02DATE"

/*
 * c_flags bits
 */
#define	CF_TRUE       (1<<0)	/* usually means component is present */
#define	CF_PARSED     (1<<1)	/* address/date has been parsed */
#define	CF_DATEFAB    (1<<2)	/* datefield fabricated */
#define CF_TRIMMED    (1<<3)	/* Component has been trimmed */

#define CF_BITS       "\020\01TRUE\02PARSED\03CF_DATEFAB\04TRIMMED"

/*
 * This structure defines one formatting instruction.
 */
struct format {
    unsigned char f_type;
    char          f_fill;
    short         f_width;	/* output field width   */
    union {
	struct comp *f_u_comp;	/* associated component */
	char        *f_u_text;	/* literal text         */
	char         f_u_char;	/* literal character    */
	int          f_u_value;	/* literal value        */
    } f_un;
    short         f_flags;	/* misc. flags          */
};

#define f_skip f_width		/* instr to skip (false "if") */

#define f_comp  f_un.f_u_comp
#define f_text  f_un.f_u_text
#define f_char  f_un.f_u_char
#define f_value f_un.f_u_value

/*
 * f_flags bits
 */

#define FF_STRALLOC	(1<<0)	/* String has been allocated */
#define FF_COMPREF	(1<<1)	/* Component reference */

/*
 * prototypes used by the format engine
 */

/*
 * These are the definitions used by the callbacks for fmt_scan()
 */

typedef char * (*formataddr_cb)(char *, char *);
typedef char * (*concataddr_cb)(char *, char *);
typedef void (*trace_cb)(void *, struct format *, int, char *, const char *);

struct fmt_callbacks {
    formataddr_cb	formataddr;
    concataddr_cb	concataddr;
    trace_cb		trace_func;
    void *		trace_context;
};

/*
 * Create a new format string.  Arguments are:
 *
 * form		- Name of format file.  Will be searched by etcpath(), see that
 *		  function for details.
 * format	- The format string to be used if no format file is given
 * default_fs	- The default format string to be used if neither form nor
 *		  format is given
 *
 * This function also takes care of processing \ escapes like \n, \t, etc.
 *
 * Returns an allocated format string.
 */

char *new_fs (char *form, char *format, char *default_fs);

/*
 * Free memory allocated by new_fs().  It allocates to a static so
 * no argument is necessary.
 */
void free_fs(void);

/*
 * Compile a format string into a set of format instructions.  Arguments are:
 *
 * fstring	- The format string (the "source code").
 * fmt		- Returns an allocated array of "struct fmt" elements.  Each
 *		  struct fmt is one format instruction interpreted by the
 *		  format engine.
 * reset	- If set to true, the format compiler will reset the
 *		  component hash table.  The component hash table contains
 *		  all of the references to message components referred to in
 *		  the format instructions.  If you have multiple format
 *		  strings that you want to compile and operate on the
 *		  same message, this should be set to false.
 *
 * Returns the total number of components referenced by all format instructions
 * since the last reset of the hash table.
 */

int fmt_compile (char *fstring, struct format **fmt, int reset);

/*
 * Interpret a sequence of compiled format instructions.  Arguments are:
 *
 * format	- Array of format instructions generated by fmt_compile()
 * scanl	- Passed-in charstring_t object (created with
 *		  charstring_create() and later destroyed with
 *		  charstring_free()) that will contain the output of the
 *		  format instructions.  Is always terminated with a
 *		  newline (\n).
 * width	- Maximum number of displayed characters.  Does not include
 *		  characters marked as non-printing or (depending on the
 *		  encoding) bytes in a multibyte encoding that exceed the
 *		  character's column width.
 * dat		- An integer array that contains data used by certain format
 *		  functions.  Currently the following instructions use
 *		  dat[]:
 *
 *		dat[0] - %(msg), %(dat)
 *		dat[1] - %(cur)
 *		dat[2] - %(size)
 *		dat[3] - %(width)
 *		dat[4] - %(unseen)
 *
 * callbacks	- A set of a callback functions used by the format engine.
 *		  Can be NULL.  If structure elements are NULL, a default
 *		  function will be used.  Callback structure elements are:
 *
 *		formataddr	- A callback for the %(formataddr) instruction
 *		concataddr	- A callback for the %(concataddr) instruction
 *		trace		- Called for every format instruction executed
 *
 * The return value is a pointer to the next format instruction to
 * execute, which is currently always NULL.
 */

struct format *fmt_scan (struct format *format, charstring_t scanl, int width,
			 int *dat, struct fmt_callbacks *callbacks);

/*
 * Free a format structure and/or component hash table.  Arguments are:
 *
 * format	- An array of format structures allocated by fmt_compile,
 *		  or NULL.
 * reset	- If true, reset and remove all references in the component
 *		  hash table.
 */

void fmt_free (struct format *fmt, int reset);

/*
 * Free all of the component text structures in the component hash table
 */

void fmt_freecomptext(void);

/*
 * Search for a component structure in the component hash table.  Arguments are:
 *
 * component	- The name of the component to search for.  By convention
 *		  all component names used in format strings are lower case,
 *		  but for backwards compatibility this search is done in
 *		  a case-SENSITIVE manner.
 *
 * This function returns a "struct comp" corresponding to the named component,
 * or NULL if the component is not found in the hash table.
 */

struct comp *fmt_findcomp(char *component);

/*
 * Search for a component structure in the component hash table.
 *
 * Identical to fmd_findcomp(), but is case-INSENSITIVE.
 */

struct comp *fmt_findcasecomp(char *component);

/*
 * Add a component entry to the component hash table
 *
 * component	- The name of the component to add to the hash table.
 *
 * If the component is already in the hash table, this function will do
 * nothing.  Returns 1 if a component was added, 0 if it already existed.
 */

int fmt_addcompentry(char *component);

/*
 * Add a string to a component hash table entry.  Arguments are:
 *
 * component	- The name of the component to add text to.  The component
 *		  is searched for in a case-INSENSITIVE manner (note that
 *		  this is different than fmt_findcomp()).  If the component
 *		  is not found in the hash table, this function will silently
 *		  return.
 * text		- The text to add to a component hash table entry.  Note that
 *                if the last character of the existing component
 *                text is a newline AND it is marked as an address
 *                component (the the CT_ADDR flag is set) existing
 *                component buffer is a newline, it will be separated
 *                from previous text by ",\n\t"; otherwise if the last
 *                character of the previous text is a newline it will
 *                simply be separated by a "\t".  This unusual processing
 *		  is designed to handle the case where you have multiple
 *		  headers with the same name (e.g.: multiple "cc:" headers,
 *		  even though that isn't technically allowed in the RFCs).
 *
 * This function is designed to be called when you start processing a new
 * component.  The function returns the integer value of the hash table
 * bucket corresponding to this component.  If there was no entry found
 * in the component hash table, this function will return -1.
 */

int fmt_addcomptext(char *component, char *text);

/*
 * Append to an existing component.  Arguments are:
 *
 * bucket	- The hash table bucket corresponding to this component,
 *		  as returned by fmt_addcomp().  If -1, this function will
 *		  return with no actions performed.
 * component	- The component to append text to.  Like fmt_addcomp, the
 *		  component is searched case-INSENSITIVELY.
 * text		- The text to append to the component.  No special processing
 *		  is done.
 *
 * This function is designed to be called when you are processing continuation
 * lines on the same header (state == FLDPLUS).
 */

void fmt_appendcomp(int bucket, char *component, char *text);

/*
 * Iterate over the complete hash table of component structures.
 *
 * Arguments are:
 *
 * comp		- Pointer to the current component structure.  The next
 *		  component in the hash table after this component.  To
 *		  start (or restart) the iteration of the hash table
 *		  this argument should be NULL.
 * bucket	- Pointer to hash bucket.  Will be managed by this function,
 *		  the caller should not modify this value.
 *
 * Returns the next component in the hash table.  This value should be
 * passed into the next call to fmt_nextcomp().  Returns NULL at the end
 * of the hash table.
 */

struct comp *fmt_nextcomp(struct comp *comp, unsigned int *bucket);

/*
 * The implementation of the %(formataddr) function.  This is available for
 * programs to provide their own local implementation if they wish to do
 * special processing (see uip/replsbr.c for an example).  Arguments are:
 *
 * orig		- Existing list of addresses
 * str		- New address(es) to append to list.
 *
 * This function returns an allocated string containing the new list of
 * addresses.
 */

char *formataddr(char *orig, char *str);

/*
 * The implementation of the %(concataddr) function.  Arguments and behavior
 * are the same as %(formataddr).  Again, see uip/replsbr.c to see how you
 * can override this behavior.
 */

char *concataddr(char *orig, char *str);
