/*
 *	Various utilities
 *
 *	Copyright
 *		(C) 1992 Joseph H. Allen
 *		(C) 2001 Marek 'Marx' Grac
 *
 *	This file is part of JOE (Joe's Own Editor)
 */

/* Destructors */

#define AUTO_DESTRUCT GC *gc = 0;

typedef struct gc GC;

struct gc {
	struct gc *next;	/* List */
	void **var;		/* Address of pointer variable */
	void (*rm)(void *val);	/* Destructor which takes pointer variable */
};

/* Add a variable to GC list */

void gc_add(GC **gc, void **var, void (*rm)(void *val));

/* Call destructors */

void gc_collect(GC **gc);

/* Version of return which calls destructors before returning */

#define RETURN(val) do { \
	if (gc) gc_collect(&gc); \
	return (val); \
	} while(0)

/* Pool allocation functions using singly-linked lists */

extern void *ITEM; /* Temporary global variable (from queue.c) */

/* Allocate item from free-list.  If free-list empty, replenish it. */

void *replenish(void **list,ptrdiff_t size);

#define al_single(list,type) ( \
	(ITEM = *(void **)(list)) ? \
	  ( (*(void **)(list) = *(void **)ITEM), ITEM ) \
	: \
	  replenish((void **)(list),sizeof(type)) \
)

/* Put item on free list */

#define fr_single(list,item) do { \
	*(void **)(item) = *(void **)(list); \
	*(void **)(list) = (void *)(item); \
} while(0)

/* JOE's version of zero-terminated string (z-string) functions.
   In older versions of JOE we had these because the library versions were slow.
   In older versions of JOE we had these because we globally used "unsigned char *" strings.
   Now we have them for ptrdiff_t lengths (instead of size_t), to avoid mixed signed / unsigned warnings. */

/* These are exactly the same as the library versions: for consistent naming */
#define zstr(a, b) strstr((a), (b))
#define zchr(s, c) strchr((s), (c))
#define zrchr(s, c) strrchr((s), (c))
#define zcat(a, b) strcat((a), (b))
/* #define zdup(s) strdup(s) */
#define zcpy(a, b) strcpy((a), (b))
#define zcmp(a, b) strcmp((a), (b))

/* char *zstr(const char *a, const char *b); */
/* char *zchr(const char *s, int c); */
/* char *zrchr(const char *s, int c); */
/* char *zcat(char *a, char *b); */
char *zdup(const char *s); /* Use joe_malloc */
/* char *zcpy(char *a, char *b); */
/* int zcmp(char *a, char *b); */

#define zlen(s) (ptrdiff_t)strlen(s)

/* Case insensitive compare, but only for ASCII */
int zicmp(const char *a, const char *b);

/* String compare for ctags file strings */
int zmcmp(const char *a, const char *b);

/* Same strncmp */
int zncmp(const char *a, const char *b, ptrdiff_t len);

/* Same as memcpy */
void *mcpy(void *a, const void *b, ptrdiff_t len);

/* Same as strncpy */
char *zncpy(char *a, const char *b, ptrdiff_t len);

/* Like strncpy, but string always ends up zero-terminated */
char *zlcpy(char *a, ptrdiff_t siz, const char *b);

/* Like strncat, but result is always zero-terminated */
char *zlcat(char *a, ptrdiff_t siz, const char *b);

/* Functions which support zero-terminated strings of ints */

ptrdiff_t Zlen(const int *s);
int Zcmp(const int *a, const int *b);
int *Zlcpy(int *a, ptrdiff_t siz, const int *b);
int *Zdup(const int *s);
char *Ztoutf8(char *a, ptrdiff_t len, const int *b);
char *Ztoz(char *a, ptrdiff_t len, const int *b);

/*
 * Functions which return minimum/maximum of two numbers
 */
unsigned int uns_min(unsigned int a, unsigned int b);
signed int int_min(signed int a, int signed b);
signed long long_max(signed long a, signed long b);
signed long long_min(signed long a, signed long b);
off_t off_max(off_t a, off_t b);
off_t off_min(off_t a, off_t b);
ptrdiff_t diff_max(ptrdiff_t a, ptrdiff_t b);
ptrdiff_t diff_min(ptrdiff_t a, ptrdiff_t b);

/* Versions of 'read' and 'write' which automatically retry when interrupted */
ptrdiff_t joe_read(int fd, void *buf, ptrdiff_t siz);
ptrdiff_t joe_write(int fd, const void *buf, ptrdiff_t siz);
int joe_ioctl(int fd, unsigned long req, void *ptr);

/* wrappers to *alloc routines */
void joe_free(void *ptr);
void *joe_malloc(ptrdiff_t size) ATTR_JOE_MALLOC;
char *joe_strdup(char *ptr) ATTR_JOE_MALLOC;
void *joe_calloc(ptrdiff_t nmemb, ptrdiff_t size) ATTR_JOE_MALLOC ATTR_ALLOC_SIZE((1, 2));
void *joe_realloc(void *ptr, ptrdiff_t size) ATTR_ALLOC_SIZE((2));

#ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t)(int);
#endif

#ifdef NEED_TO_REINSTALL_SIGNAL
#define REINSTALL_SIGHANDLER(sig, handler) joe_set_signal(sig, handler)
#else
#define REINSTALL_SIGHANDLER(sig, handler) do {} while(0)
#endif

/* wrapper to hide signal interface differences */
int joe_set_signal(int signum, sighandler_t handler);

/* Helpers */
const char *skip_digits(const char *p);

/* Simple parsers */
int parse_ws(const char * *p,int cmt);
int parse_wsn(const char * *p,int cmt);
int parse_wsl(const char * *p,int cmt);
int parse_ident(const char **p,char *buf,ptrdiff_t len);
int parse_kw(const char **p,const char *kw);
int parse_tows(const char **p,char *buf);
int parse_field(const char **p,const char *field);
int parse_char(const char **p,char c);
int parse_int(const char **p,int *buf);
int parse_diff(const char **p,ptrdiff_t *buf);
int parse_off_t(const char **p,off_t *buf);
off_t ztoo(const char *s);
off_t zhtoo(const char *s);
long ztol(const char *s);
long zhtol(const char *s);
ptrdiff_t ztodiff(const char *s);
ptrdiff_t zhtodiff(const char *s);
int ztoi(const char *s);
int zhtoi(const char *s);
ptrdiff_t parse_string(const char **p,char *buf,ptrdiff_t len);
ptrdiff_t parse_Zstring(const char **p,int *buf,ptrdiff_t len);
int parse_range(const char **p,int *first,int *second);
int parse_class(const char **p, struct interval **array, ptrdiff_t *size);
void emit_string(FILE *f,const char *s,ptrdiff_t len);

void jsort(void *base, ptrdiff_t num, ptrdiff_t size, int (*compar)(const void *a, const void *b));

off_t oabs(off_t);
