/* strfunc.h.  Generated by configure.  */
/*-
 * Copyright (c) 1999, 2000, 2001, 2002 Lev Walkin <vlm@spelio.net.ru>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: strfunc.h.in,v 1.22 2003/01/13 00:31:05 vlm Exp $
 */

#ifndef __STRFUNC_H__
#define __STRFUNC_H__

#include <stdio.h>
#include <sys/types.h>

/*
 * Define to `int' if <sys/types.h> doesn't define.
 * Substituted by configure.
 */
/* #undef ssize_t */

#ifdef __cplusplus
extern "C" {
#endif

	/***********************/
	/*** 1. String lists ***/
	/***********************/

typedef struct {
    char **list;
    size_t	count;
    size_t	listlen;
	size_t	maxlen;
	size_t	*lens;
} svect;

typedef struct {
	svect *key;
	svect *val;
} svectpair;

/* Backward compatibility */
typedef	svect slist;
typedef	svectpair slistpair;

svect	*sinit(void);		/* Create empty structure */
void	sclear(svect *);	/* Clear elements of filled structure */
void	sfree(svect *);		/* Destroy entire object completely */

/* Add element to the end of list */
int	sadd(svect *, const char *toadd);	/* with strdup(toadd) */
int	sadd2(svect *, void *toadd, size_t len); /* With length. */
int	sadd_attach(svect *, void *toadd, size_t len); /* Without strdup() */

/* Add to a svectpair. If flags, then treat values as being pre-allocated */
int saddp(svectpair *, char *key, char *val, int flags);

/* Delete element */
int	sdel(svect *, size_t idx);	/* Delete specified element */
/* Insert element */
ssize_t sins(svect *, const char *, size_t idx); /* Insert element before idx */
/* Fetch element by index */
#define sget(sl, idx)	((sl)->list[(idx)])

/*
 * Split and join functions.
 */

/* Split functions, my aknowledgements to Larry Wall! */
svect *split(const char *what, const char *delim, int strict); /* creates new (svect *) */
int splitf(svect *sl, const char *what, const char *delim, int strict);
int splitquotable(svect *, const char *);	/* bash-like */
int split_network(const char *, unsigned int *ip, unsigned int *mask);
int sf_iaton(const char *cp, unsigned int *pin); /* aka inet_aton */

/* Join function */
char *sjoin(svect *, char *delimiter); /* Join values together */

/*
 * Search the list.
 */

/* Find element */
ssize_t sfind(svect *, const char *);	/* Case-sensitive */
ssize_t scfind(svect *, const char *);	/* Case-insensitive */

/* Find tofind in the a and display b's element with the same index */
char	*sget2(svect *a, const char *tofind, svect *b);
char	*scget2(svect *, const char *, svect *);	/* Case-insensitive */
char	*sgetp(svectpair *, const char *tofind);
char	*scgetp(svectpair *, const char *tofind);	/* Case-insensitive */

/*
 * Manipulate the entire list.
 */

/* Add values from the char** */
int	simport(svect *, char **vals);	/* free()'s vals!!! */

/* Copy svect */
svect	*scopy(svect *src);

/* Make char ** from the list */
char	**sarray(svect *, size_t startidx);	/* leak-safe */
char	**mkarray(svect *, size_t startidx);	/* malloc()'ed "giveaway" */


/**************************/
/*** Smart data buffers ***/
/**************************/

typedef struct {
	char *buf;
	size_t len;		/* Meaningful length */
	size_t size;	/* Allocated size of the *buf. */
	size_t off;		/* Offset from the start (not related with len) */
} sbuf;

#define	sbuf2ptr(sb)	((sb)->buf + (sb)->off)

sbuf *sbuf_init(void);
void sbuf_free(sbuf *sb); /* Destroy buffer */

/* Detach the sb->buf pointer and reinitialize buffer */
char *sbuf_detach(sbuf *sb, size_t *optLength, size_t *optSize);

int sbuf_clear(sbuf *);	/* Clear buffer contents & truncate memory */
int sbuf_zero(sbuf *);	/* Clear buffer contents */

ssize_t sbuf_add(sbuf *, const char *string);	/* Add a copy of the string */
ssize_t sbuf_add2(sbuf *, void *data, size_t nbytes);	/* */
#define	SBUF_ADDCHAR(s,c)	if(s->len >= s->size) sbuf_extend(s, s->size); s->buf[s->len++] = c;

ssize_t sbuf_extend(sbuf *, size_t upto);	/* Extend buffer up to upto. */
ssize_t sbuf_sprintf(sbuf *, char *fmt, ...);	/* Self-descriptive. */
char *sbuf_fgets(sbuf *, FILE *stream);	/* Read till the end of line. */
char *sbuf_fetch(sbuf *sb, size_t len, char *optDelimiter,
	size_t *optLength, int flags);	/* Fork a substring from the buffer */


/***********************************/
/*** Plain string array handlers ***/
/***********************************/

char **charize(const char *);	/* Make null-terminated char** */
void free_values(char **);
size_t	count_values(char **);
int copy_values(char **from, char ***to);
char	*join(char **, char *delimiter);  /* Join values with delimiter */
ssize_t find(char **, const char *);      /* Work on char[]'s */
ssize_t cfind(char **, const char *);     /* Case-insensitive */


/*****************/
/* Misc. helpers */
/*****************/

int eq(const char *a, const char *b);	/* Equality test */
int ecq(const char *a, const char *b);	/* Case-insensitive */
int ecq2(const char *a, const char *b);	/* b's lowercase assumed */

char *strndup(const char *, size_t num);/* strdup() num bytes from the string */
char *sf_strdup(const char *);		/* safe strdup() */
void *sf_malloc(size_t);		/* safe malloc() */
void *sf_calloc(size_t, size_t);	/* safe calloc() */
void *sf_realloc(void *, size_t);	/* safe realloc() */

int countchar(const char *, char what2countChar);
int countchar2(const char *, const char *what2countSet);
int countstr(const char *, const char *what2countStr);

char *genstr(int number);	/* Make string containing integer */

char *brace(char *, char rbrace);	/* find a closing bracket */
char *bracen(char *, char rbrace, size_t nlen);	/* find a closing bracket */

/* Need not to be free()'d */
char *replace(char *str, char *what, char *to);

char *replace_detach(void);

char *limittextwidth(char *text, size_t width);	/* corrupts text! */


/************************/
/*** Time conversions ***/
/************************/

/* Convert RFC-822/1123, ISO-8601, X.208 or other types of date to time_t */
time_t strtotime(char *datestring);

/* Convert time_t to string. Flags are defined below. */
char * timetostr(time_t value, int flags);
/*
 * Flags are:
 */
#define TFMT_UNIX    0x000 /* unix_time format */
#define TFMT_RFC822  0x001 /* Format described in RFC-822/1123 */
#define TFMT_ISO8601 0x002 /* Format described in ISO-8601 */
#define TFMT_CTIME   0x003 /* ctime(3) and asctime(3) format */
#define TFMT_X208    0x004 /* Format specified by X.208 */
/* Pure flags to be OR'ed with above */
#define TFMT_LOCAL   0x100 /* Construct string for local TZ instead of GMT */
#define TFMT_UF      0x200 /* User-friendly (detailed) output */
#define TFMT_OLD822GMT 0x400 /* Use old "...MMM DD YYYY GMT" for use in HTTP headers */

/*************************/
/*** CGI form handling ***/
/*************************/


/* Parse QUERY_STRING or stdin dependent on REQUEST_METHOD */

/* Return names of all form fields */
svect *params(void);

/* Get specified form field */
char *param(char *fieldname);

/* Return a list of values of specified field */
/* _flags are:
** 0: get decoded value
** 1: get original unmodified (url-encoded) value
** 2: get field content type
*/
svect *param2(char *fieldname, int _flags);

/* Cookies support */
svect	*cookies(void);
char	*cookie(char *name);
int set_cookie(char *name, char *value, char *optDomain, char *optPath, time_t optMaxAge, char *optComment, int optSecure);


/* Convert '&' to '&amp;', '<' to '&lt;', etc. */
char *html_quote(char *);	/* Leak-safe */
char *html_quote_detach(void);

/* Parse HTTP_ACCEPT_LANGUAGE */
svect *getlanguageprefs(void);	/* Don't free() the result! */

/*************************/
/*** Various encodings ***/
/*************************/

/* Encode and decode %%'s in URL */
char *url_decode(char *urlstring);		/* leak-safe. */
char *url_encode(char *s);			/* leak-safe. */

char *base64_encode(void *data, size_t size);	/* leak-safe */
void *base64_decode(char *string, size_t *size);/* leak-safe */
void *base64_detach(size_t *size);	/* Detach the internal buffer */

char *quoted_printable_decode(char *string);	/* leak-safe */
char *mime_word_decode(char *string);		/* leak-safe */

/*************************/
/*** Encoding handlers ***/
/*************************/

char *lang_recode(char *string, char table[]);
char *windows_1251_to_koi8_r(char *string); /* leak-safe */
char *koi8_r_to_windows_1251(char *string); /* leak-safe */
char *cp_866_to_koi8_r(char *string); /* leak-safe */
char *koi8_r_to_cp_866(char *string); /* leak-safe */
char *iso_8859_5_to_koi8_r(char *string); /* leak-safe */


/*********************************/
/*** Text formatting functions ***/
/*********************************/

typedef struct fmt_base_internal	fmt_base;

fmt_base *format_init(void);	/* Init base format structure */
void      format_free(fmt_base *base);	/* Destroy it */

/*
 * Add a rule how to handle ${X}, where '{' and '}' must be defined herein,
 * and X will be passed as 'found' directly into char **function(char *found);
 */
int	  format_metarule(fmt_base *base,
	char startwith, char endwith,	/* Characters, like '{' and '}' */
	char **(*function)(char *found, void *optKeyPassed));

/*
** Do the necessary formatting an return the result stored in internal buffer
** that is not to be freed.
*/
char *formatf(fmt_base *base, char *text_template, void *optKeyToPass);

char *format_lastresult(fmt_base *, size_t *optSize);
size_t format_lastsize(fmt_base *);
char *format_detach(fmt_base *, size_t *optSize);

/*
 * Overview of format usage (`man formatf` for more).
 * Say, we have invoked
 *
 * 	format_metarule( base=format_init(), '{', '}', ffunc);
 *
 * Then, we will be able to build format strings like in the following examples:
 *
 * EXAMPLE 1. The simple cases.
 *
 * 	formatf(base, "something", ...) will return "something".
 *
 * 	formatf(base, "some ${attr}", ...) will return "some value",
 *		where 'value' is the value returned by ffunc("attr").
 *
 * 	formatf(base, "some ${attr} and ${a2}", ...) will return
 *		"some value and value2", where 'value' and 'value2' are the
 *		values returned by ffunc("attr") and ffunc("a2") respectively.
 *
 * EXAMPLE 2. Joining values.
 *
 * Let's get ffunc("here", ...) returning an array { "v1", "v2", NULL }, then
 *
 * 	formatf(base, "List is ${here}", ...) will return "List is v1, v2".
 *
 * Please point out that 'v2' and 'v2' are separated by ', ', this is the
 * default separator. To change separator please use a plus ('+') sign like
 * below:
 *
 * 	formatf(base, "List is ${here+|}", ...) will return "List is v1|v2".
 * 	formatf(base, "${here+,&nbsp;}", ...) will return "v1,&nbsp;v2".
 *
 * EXAMPLE 3. Selecting values.
 *
 * Again, imagine that ffunc("here") returns an array { "v1", "2v", NULL }, then
 *
 * 	formatf(base, "Value 0 is ${here[0]}", ...) will return "Value 0 is v1" and
 * 	formatf(base, "Value 0 is ${here[1]}", ...) will return "Value 0 is 2v".
 *
 * EXAMPLE 4. The switching case.
 *
 * 	formatf(base, "${a?b:c}", ...) will return "b" if ffunc("a", ...) returns
 *  with non-empty list, or "c" if ffunc("a", ...) returns NULL or empty list.
 *
 * 	formatf(base, "${a?${b}:${c}}", ...) will return "v1", which is an output
 *	of ffunc("b"), if ffunc("a", ...) returns with non-empty list, or "v2",
 *	which is an output of ffunc("c", ...), if ffunc("a", ...) returns NULL.
 *
 * As you see, those cases are fully recursive.
 *
 * EXAMPLE 5. The switching case with [in]equality test.
 *
 * 	formatf(base, "${a==5?b:c}", ...) will return "b" if ffunc("a", ...)
 *  returns with a non-empty list containing "5" in one of its values.
 *  Otherwise, it will return "c".
 *
 * EXAMPLE 6. The real usage.
 *
 * Please guess the behaviour of the following function:
 *
 *	formatf(base, "${param?Value is ${param}.:Parameter empty. Access
 *	${left==0?restricted:granted with ${left} parrots left}.}", NULL)
 *
 */

/*********************************/
/*** Config parsing functions  ***/
/*********************************/

/* Read the config file in memory. Returns -1 on error and 0 otherwise */
int cfgread(const char *fname);

/*
 * Get attribute defined as
 * attribute = "value";
 * Returns NULL if not value found.
 */
char *cfgget(char *attr);

/*
 * Get attribute defined as
 * attribute { value1,
 * value2, value3 };
 * Returns empty svect* if not found.
 * You are responsible for sfree()'ing this structure when necessary.
 */
svect *cfgget2(char *attr);


/*******************************/
/*** File position functions ***/
/*******************************/

/*
** initfdpos() creates a position indicator file "filename.ext", and
** returns its file descriptor. If the position file is already exists,
** then initfdpos() advances stream's position according to the information
** derived from that file.
** Return values: position file descriptor, or -1 in case of failure.
*/
int initfdpos(const char *filename, int stream, const char *ext);
int initFILEpos(const char *filename, FILE *stream, const char *ext);

/*
** adjfdpos() writes the current position within the file referenced by stream
** into the posfd. If doSync is not zero, it also does fsync(posfd) to submit
** changes to disk.
** Return values: 0 (Success) or -1 in case of any errors.
*/
int adjfdpos(int stream, int posfd, int doSync);
int adjFILEpos(FILE *stream, int posfd, int doSync);


/********************************/
/*** String editing functions ***/
/********************************/

/*
** Here is the functions that provide a useful subset of sed(1) functionality.
*/

typedef void sed_t;

sed_t *sed_compile(const char *expr);
char *sed_exec(sed_t *se, const char *string);	/* Evaluate [and substitute] */
svect *sed_results(sed_t *se);	/* Fetch results again */
svect *sed_border_results(sed_t *se);	/* Fetch border results */
void sed_free(sed_t *se);

/* Undocumented */
int sed_handler(sed_t *se,
	char *(*function)(svect *found));

/********************************/
/*** LibStrfunc control flags ***/
/********************************/

#define	SF_GET_MEMORY_FAILURE_BEHAVIOR	1
#define	SF_SET_MEMORY_FAILURE_BEHAVIOR	2
#define	SF_ARG_MFB_ABORT	0	/* Default is to call abort() */
#define	SF_ARG_MFB_ENOMEM	1	/* Just return ENOMEM */
#define	SF_ARG_MFB_TRY_ABORT	2	/* Try several times, then abort */
#define	SF_ARG_MFB_TRY_ENOMEM	3	/* Try several times, then ENOMEM */
#define	SF_ARG_MFB_TRY_NOFAIL	4	/* Try forever */

#define	SF_GET_MEMORY_FAILURE_TRIES	3	/* Default: 10 try times */
#define	SF_SET_MEMORY_FAILURE_TRIES	4

	/* Use this if you want to quickly do huge amount of strtotime().
	 * Will omit the time() system call on each call.
	 */
#define	SF_GET_STRTOTIME_ZINFO_CACHING	5	/* Default: 0 */
#define	SF_SET_STRTOTIME_ZINFO_CACHING	6

int	strfunc_ctl(int request, int *optArg);
/*
 * Set a callback to be invoked upon memory failure.
 */
void	strfunc_memory_failure_callback(void (*cb)(void));

/**************************/
/*** Libstrfunc Version ***/
/**************************/

int strfunc_version(void);	/* Run-time version */
#define	STRFUNC_VERSION	745

#ifdef __cplusplus
}
#endif

#endif
