/*
   Common defines for the kbuild pre-processors.

   (c) Keith Owens <kaos@ocs.com.au> May 2001.
   Released under GPL version 2, (you know the rest).
 */

#ifndef _PP_MAKEFILE_H
#define _PP_MAKEFILE_H

#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

/* ---- Miscellaneous functions and declarations ---- */

#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#ifndef DMALLOC
static inline void *
k_malloc(size_t size)
{
	void *p = malloc(size);
	if (!p) {
		fprintf(stderr, "k_malloc: out of memory\n");
		exit(1);
	}
	return p;
}

static inline void *
k_realloc(void *old, size_t size)
{
	void *p = realloc(old, size);
	if (!p) {
		fprintf(stderr, "k_realloc: out of memory\n");
		exit(1);
	}
	return p;
}

static inline char *
k_strdup(const char *str)
{
	char *p = strdup(str);
	if (!p) {
		fprintf(stderr, "k_strdup: out of memory\n");
		exit(1);
	}
	return p;
}

#else				/* !DMALLOC */

/* When using dmalloc, map direct to the underlying routines and omit the check
 * for out of memory.  Then dmalloc logs the calling routine instead of k_...
 */

#define k_malloc(size)		malloc(size)
#define k_realloc(old, size)	realloc(old,size)
#define k_strdup(str)		strdup(str)

#endif				/* DMALLOC */

extern int errors;

extern const char *arch;
extern int arch_len;

extern int pp_getenv(void);
extern void pp_freeenv(void);

extern int verbose;

static inline void
VERBOSE(int level, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	if (verbose >= level) {
		vfprintf(stderr, format, ap);
	}
	va_end(ap);
}

/* fgets with automatic resize of the buffer to handle long lines.
 * Returns 0 if a line was read, 1 at end of file, -1 at error.
 */

static inline int
fgets_long_line(char **line, int *line_size, FILE * f)
{
	int eol = 0, data_read = 0, offset = 0;
	while (!eol) {
		if (!fgets(*line + offset, *line_size - offset, f)) {
			eol = 1;
			if (ferror(f)) {
				return (-1);
			} else if (data_read && !strchr(*line, '\n')) {
				/* No specific error for missing end of file, overload EOVERFLOW */
				errno = EOVERFLOW;
				return (-1);
			}
			if (!data_read) {
				return (1);
			}
		} else {
			data_read = 1;
			if (strchr(*line, '\n')) {
				eol = 1;
			} else {
				offset = *line_size - 1;
				*line_size += 4096;
				*line = k_realloc(*line, *line_size);
			}
		}
	}
	return (0);
}

static inline void
mkdir_p(char *name, const char *program)
{
	char *p = name, *p1;
	while ((p1 = strchr(p, '/'))) {
		*p1 = '\0';
		if (p != p1 && mkdir(name, 0755) && errno != EEXIST) {
			fprintf(stderr, "%s: mkdir(%s) failed, %m\n", program,
				name);
			return;
		}
		*p1 = '/';
		p = p1 + 1;
	}
}

#if PP_GETOPT_LONG == 0
/* Building on a system without getopt_long.  Drop back to getopt. */
struct option {
	const char *name;
	int has_arg;
	int *flag;
	int val;
};

#define getopt_long(argc, argv, optstring, longopts, longindex) \
({ \
 	(void)longopts; \
	(void)longindex; \
	getopt(argc, argv, optstring); \
})
#endif

/* ---- Declarations for walking the file system ---- */

#define MAX_SRCTREE 999
extern const char *srctree[MAX_SRCTREE + 1];
extern int high_srctree;
extern int common_src_obj;
extern const char *treename;
extern int treename_index;
extern int l_srctree[];

/* Tuck the object tree at the high end of the source tree array to get a
 * non-zero index.
 */
#define objtree_treename_index MAX_SRCTREE
#define objtree (srctree[objtree_treename_index])
#define l_objtree l_srctree[objtree_treename_index]

#define CONFIG_SETTINGS		"/config_settings/"

#ifdef DMALLOC
#include <dmalloc.h>
#endif

#endif				/* _PP_MAKEFILE_H */
