/* $Id: func.c 1955 2007-02-28 17:07:04Z coudercd $ */

/*
 * Copyright (c) 2003-2006 Damien Couderc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - 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.
 *    - Neither the name of the copyright holder(s) nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
 * COPYRIGHT HOLDERS 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.
 *
 */


#include <stdlib.h>

#include "compat/pmk_stdio.h"
#include "compat/pmk_string.h"
#include "compat/pmk_unistd.h"
#include "autoconf.h"
#include "cfgtool.h"
#include "codebuild.h"
#include "common.h"
#include "detect.h"
#include "func.h"
#include "functool.h"
#include "hash.h"
#include "pkgconfig.h"
#include "premake.h"
#include "tags.h"


/*#define SHLIB_DEBUG 1*/


/***************
 * parser data *
 ***********************************************************************/

/* common required options */
kw_t	req_name[] = {
	{KW_OPT_NAME,	PO_STRING}
};

/* CHECK_BIN options */
kw_t	opt_chkbin[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_VARIABLE,	PO_STRING}
};

kwopt_t	kw_chkbin = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chkbin,
	sizeof(opt_chkbin) / sizeof(kw_t)
};

/* CHECK_HEADER options */
kw_t	opt_chkhdr[] = {
	{KW_OPT_CFLAGS,		PO_STRING},
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_SUBHDR,		PO_LIST},
	{KW_OPT_FUNCTION,	PO_STRING | PO_LIST},
	{KW_OPT_LANG,		PO_STRING},
	{KW_OPT_MACRO,		PO_LIST},
	{KW_OPT_REQUIRED,	PO_BOOL}
};

kwopt_t	kw_chkhdr = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chkhdr,
	sizeof(opt_chkhdr) / sizeof(kw_t)
};

/* CHECK_LIB options */
kw_t	opt_chklib[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_FUNCTION,	PO_STRING | PO_LIST},
	{KW_OPT_LANG,		PO_STRING},
	{KW_OPT_LIBS,		PO_STRING},
	{KW_OPT_MACRO,		PO_LIST},
	{KW_OPT_REQUIRED,	PO_BOOL}
};

kwopt_t	kw_chklib = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chklib,
	sizeof(opt_chklib) / sizeof(kw_t)
};

/* CHECK_CONFIG options */
kw_t	opt_chkcfg[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_CFLAGS,		PO_STRING},
	{KW_OPT_LIBS,		PO_STRING},
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_VARIABLE,	PO_STRING},
	{KW_OPT_VERSION,	PO_STRING}
};

kwopt_t	kw_chkcfg = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chkcfg,
	sizeof(opt_chkcfg) / sizeof(kw_t)
};

/* CHECK_PKG_CONFIG options */
kw_t	opt_chkpc[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_CFLAGS,		PO_STRING},
	{KW_OPT_LIBS,		PO_STRING},
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_VERSION,	PO_STRING}
};

kwopt_t	kw_chkpc = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chkpc,
	sizeof(opt_chkpc) / sizeof(kw_t)
};

/* CHECK_TYPE options */
kw_t	opt_chktyp[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_HEADER,		PO_STRING},
	{KW_OPT_LANG,		PO_STRING},
	{KW_OPT_MEMBER,		PO_STRING},
	{KW_OPT_REQUIRED,	PO_BOOL}
};

kwopt_t	kw_chktyp = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chktyp,
	sizeof(opt_chktyp) / sizeof(kw_t)
};

/* CHECK_VARIABLE options */
kw_t	opt_chkvar[] = {
	{KW_OPT_DEFS,		PO_LIST},
	{KW_OPT_DEPEND,		PO_LIST},
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_VALUE,		PO_STRING}
};

kwopt_t	kw_chkvar = {
	req_name,
	sizeof(req_name) / sizeof(kw_t),
	opt_chkvar,
	sizeof(opt_chkvar) / sizeof(kw_t)
};

/* BUILD_LIB_NAME options */
kw_t	req_bldlib[] = {
	{KW_OPT_NAME,		PO_STRING}
};
kw_t	opt_bldlib[] = {
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_MAJOR,		PO_STRING},
	{KW_OPT_MINOR,		PO_STRING},
	{KW_SL_STATIC,	    PO_STRING},
	{KW_SL_SHARED,	    PO_STRING},
	{KW_SL_VERSION,	    PO_BOOL}
};

kwopt_t	kw_bldlib = {
	req_bldlib,
	sizeof(req_bldlib) / sizeof(kw_t),
	opt_bldlib,
	sizeof(opt_bldlib) / sizeof(kw_t)
};

/* BUILD_SHLIB_NAME options */
kw_t	req_bldshl[] = {
	{KW_OPT_NAME,		PO_STRING}
};
kw_t	opt_bldshl[] = {
	{KW_OPT_REQUIRED,	PO_BOOL},
	{KW_OPT_MAJOR,		PO_STRING},
	{KW_OPT_MINOR,		PO_STRING},
	{KW_SL_VERS_FULL,	PO_STRING},
	{KW_SL_VERS_NONE,	PO_STRING}
};

kwopt_t	kw_bldshl = {
	req_bldshl,
	sizeof(req_bldshl) / sizeof(kw_t),
	opt_bldshl,
	sizeof(opt_bldshl) / sizeof(kw_t)
};

/* keyword list */
prskw	kw_pmkfile[] = {
	{"DEFINE",				PMK_TOK_DEFINE,	PRS_KW_NODE, PMK_TOK_SETVAR,	NULL},
	{"SETTINGS",			PMK_TOK_SETNGS,	PRS_KW_NODE, PMK_TOK_SETPRM,	NULL},
	{"IF",					PMK_TOK_IFCOND,	PRS_KW_NODE, PRS_TOK_NULL,		NULL},
	{"ELSE",				PMK_TOK_ELCOND,	PRS_KW_NODE, PRS_TOK_NULL,		NULL},
	{"SWITCHES",			PMK_TOK_SWITCH,	PRS_KW_CELL, PRS_TOK_NULL,		NULL},
	{"CHECK_BINARY",		PMK_TOK_CHKBIN,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chkbin},
	{"CHECK_HEADER",		PMK_TOK_CHKINC,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chkhdr},
	{"CHECK_LIB",			PMK_TOK_CHKLIB,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chklib},
	{"CHECK_CONFIG",		PMK_TOK_CHKCFG,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chkcfg},
	{"CHECK_PKG_CONFIG",	PMK_TOK_CHKPKG,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chkpc},
	{"CHECK_TYPE",			PMK_TOK_CHKTYP,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chktyp},
	{"CHECK_VARIABLE",		PMK_TOK_CHKVAR,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_chkvar},
	{"BUILD_LIB_NAME",	    PMK_TOK_BLDLIB,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_bldlib},
	{"BUILD_SHLIB_NAME",	PMK_TOK_BLDSLN,	PRS_KW_CELL, PRS_TOK_NULL,		&kw_bldshl}
};

size_t	nbkwpf = sizeof(kw_pmkfile) / sizeof(prskw);


/******************
 * misc functions *
 ***********************************************************************/

/*****************
 * func_wrapper()*
 ***********************************************************************
 DESCR
	wrapper from token to functions

 IN
	pcell : cell structure
	pgd : global data

 OUT
	boolean
 ***********************************************************************/

bool func_wrapper(prscell *pcell, pmkdata *pgd) {
	bool	rval;
	pmkcmd	cmd;

	cmd.token = pcell->token;
	cmd.label = pcell->label;

	switch (cmd.token) {
		case PMK_TOK_DEFINE :
			rval = pmk_define(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_SWITCH :
			rval = pmk_switches(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_SETNGS :
			rval = pmk_settings(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_IFCOND :
			rval = pmk_ifcond(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_ELCOND :
			rval = pmk_elcond(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_SETVAR :
			rval = pmk_set_variable(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_SETPRM :
			rval = pmk_set_parameter(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKBIN :
			rval = pmk_check_binary(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKINC :
			rval = pmk_check_header(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKLIB :
			rval = pmk_check_lib(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKCFG :
			rval = pmk_check_config(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKPKG :
			rval = pmk_check_pkg_config(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKTYP :
			rval = pmk_check_type(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_CHKVAR :
			rval = pmk_check_variable(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_BLDLIB :
			rval = pmk_build_lib_name(&cmd, pcell->data, pgd);
			break;
		case PMK_TOK_BLDSLN :
			rval = pmk_build_shlib_name(&cmd, pcell->data, pgd);
			break;
		default :
			errorf("unknown token %d", cmd.token);
			rval = false;
	}

	return(rval);
}


/******************
 * process_node() *
 ***********************************************************************
 DESCR
 	processing of given node

 IN
	pnode : node structure
	pgd : global data

 OUT
	boolean
 ***********************************************************************/

bool process_node(prsnode *pnode, pmkdata *pgd) {
	prscell	*pcell;

	/* init pcell with the first cell of pdata */
	pcell = pnode->first;

	while (pcell != NULL) {
		if (func_wrapper(pcell, pgd) == false)
			return(false);

		pcell = pcell->next;
	}

	return(true);
}


/*****************
 * node functions
 *
 * IN
 *	cmd : command structure
 *	pnode : node structure
 *	pgd : global data
 *
 * OUT
 *	boolean
 ***********************************************************************/

/****************
 * pmk_define() *
 ***********************************************************************
 DESCR
	define variables
 ***********************************************************************/

bool pmk_define(pmkcmd *cmd, prsnode *pnode, pmkdata *pgd) {
	pmk_log("\n* Parsing define\n");

	return(process_node(pnode, pgd));
}


/******************
 * pmk_settings() *
 ***********************************************************************
 DESCR
	pmk settings
 ***********************************************************************/

bool pmk_settings(pmkcmd *cmd, prsnode *pnode, pmkdata *pgd) {
	pmk_log("\n* Parsing settings\n");

	return(process_node(pnode, pgd));
}


/****************
 * pmk_ifcond() *
 ***********************************************************************
 DESCR
	if condition
 ***********************************************************************/

bool pmk_ifcond(pmkcmd *cmd, prsnode *pnode, pmkdata *pgd) {
	if (label_check(pgd->labl, cmd->label) == true) {
		pmk_log("\n< Begin of 'IF' condition [%s]\n", cmd->label);
		process_node(pnode, pgd);
		pmk_log("\n> End of 'IF' condition [%s]\n", cmd->label);
	} else {
		pmk_log("\n- Skipping 'IF' condition [%s]\n", cmd->label);
	}

	return(true);
}


/****************
 * pmk_elcond() *
 ***********************************************************************
 DESCR
	else condition
 ***********************************************************************/

bool pmk_elcond(pmkcmd *cmd, prsnode *pnode, pmkdata *pgd) {
	if (label_check(pgd->labl, cmd->label) == false) {
		pmk_log("\n< Begin of 'ELSE' condition [%s]\n", cmd->label);
		process_node(pnode, pgd);
		pmk_log("\n> End of 'ELSE' condition [%s]\n", cmd->label);
	} else {
		pmk_log("\n- Skipping 'ELSE' condition [%s]\n", cmd->label);
	}

	return(true);
}


/*****************
 * cell functions
 *
 * IN
 *	cmd : command structure
 *	ht : command options
 *	pgd : global data
 *
 * OUT
 *	boolean
 ***********************************************************************/

/******************
 * pmk_switches() *
 ***********************************************************************
 DESCR
	switches
 ***********************************************************************/

bool pmk_switches(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	char			*value;
	hkeys			*phk;
	pmkobj			*po;
	unsigned int	 i,
					 n = 0;

	pmk_log("\n* Parsing switches\n");

	phk = hash_keys(ht);

	for(i = 0 ; i < phk->nkey ; i++) {
		if (hash_get(pgd->labl, phk->keys[i]) == NULL) {
			po = hash_get(ht, phk->keys[i]);
			switch(po_get_type(po)) {
				case PO_BOOL :
					value = bool_to_str(po_get_bool(po));
					break;
				case PO_STRING :
					value = po_get_str(po);
					break;
				default :
					errorf("bad type for switch '%s'.", phk->keys[i]);
					return(false);
					break;
			}

			if (hash_update_dup(pgd->labl, phk->keys[i], value) != HASH_ADD_FAIL) {
				pmk_log("\tAdded '%s' switch.\n", phk->keys[i]);
				n++;
			} else {
				errorf(HASH_ERR_UPDT_ARG, phk->keys[i]);
				return(false);
			}
		} else {
			pmk_log("\tSkipped '%s' switch (overriden).\n", phk->keys[i]);
		}
	}
	pmk_log("\tTotal %d switch(es) added.\n", n);

	hash_free_hkeys(phk);

	return(true);
}


/**********************
 * pmk_check_binary() *
 ***********************************************************************
 DESCR
	check binary
 ***********************************************************************/

bool pmk_check_binary(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool	 required,
			 rslt;
	char	*filename,
			*varname,
			*vtmp,
			*bpath,
			 binpath[MAXPATHLEN];

	pmk_log("\n* Checking binary [%s]\n", cmd->label);
	required = require_check(ht);

	filename = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (filename == NULL) {
		errorf("NAME not assigned in label '%s'", cmd->label);
		return(false);
	}
	record_def_adv(pgd->htab, TAG_TYPE_BIN, filename, NULL, NULL, NULL);

	/* check if a variable name is given */
	varname = po_get_str(hash_get(ht, KW_OPT_VARIABLE));
	if (varname == NULL) {
		vtmp = conv_to_tag(filename);
		if (vtmp == NULL) {
			errorf("failed to generate definition name for "
				"'%s' in label '%s'", filename, cmd->label);
			return(false);
		}
		/* if not then use default naming scheme */
		varname = strdup(vtmp);
		if (varname == NULL) {
			errorf(ERRMSG_MEM);
			return(false);
		}
	}

	bpath = hash_get(pgd->htab, PMKCONF_PATH_BIN);
	if (bpath == NULL) {
		errorf("%s not available.", PMKCONF_PATH_BIN);
		return(false);
	}

	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, filename, NULL));
	}

	/* try to locate binary */
	pmk_log("\tFound binary '%s' : ", filename);
	if (get_file_path(filename, bpath, binpath, sizeof(binpath)) == false) {
		pmk_log("no.\n");
		rslt = process_required(pgd, cmd, required, filename, NULL);
		if (rslt == true) {
			/* set path as empty for the key given by varname */
			if (hash_update_dup(pgd->htab, varname, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, varname);
				return(false);
			}
		}
		return(rslt);
	} else {
		pmk_log("yes.\n");
		/* define for template */
		record_def_data(pgd->htab, filename, DEFINE_DEFAULT);
		record_def_adv(pgd->htab, TAG_TYPE_BIN, filename, NULL, NULL, binpath);

		/* recording path of config tool under the key given by varname */
		if (hash_update_dup(pgd->htab, varname, binpath) == HASH_ADD_FAIL) {
			errorf(HASH_ERR_UPDT_ARG, varname);
			return(false);
		}
		label_set(pgd->labl, cmd->label, true);
		return(true);
	}
}


/**********************
 * pmk_check_header() *
 ***********************************************************************
 DESCR
	check header file
 ***********************************************************************/

bool pmk_check_header(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool		 required,
				 rslt = true,
				 rbis,
				 rval;
	char		 inc_path[MAXPATHLEN] = "",
				*lang,
				*pstr,
				*target = NULL;
	code_bld_t	 scb;
	dynary		*funcs,
				*macros,
				*shdrs,
				*defs;
	int			 i,
				 n;

	pmk_log("\n* Checking header [%s]\n", cmd->label);

	code_bld_init(&scb, pgd->buildlog);

	required = require_check(ht);

	/* get include filename */
	pstr = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (pstr == NULL) {
		errorf("%s not assigned in label '%s'", KW_OPT_NAME, cmd->label);
		return(false);
	}
	scb.header = pstr;
	record_def_data(pgd->htab, scb.header, NULL);
	record_def_adv(pgd->htab, TAG_TYPE_HDR, scb.header, NULL, NULL, NULL);

	/* any macro(s) to check ? */
	macros = po_get_list(hash_get(ht, KW_OPT_MACRO));
	if (macros != NULL) {
		for (i = 0 ; i < (int) da_usize(macros) ; i++) {
			pstr = da_idx(macros, i);
			record_def_data(pgd->htab, pstr, NULL);
			record_def_adv(pgd->htab, TAG_TYPE_HDR_MCR, scb.header, pstr, NULL, NULL);
		}
	}

	/* optional header sub dependencies */
	shdrs = po_get_list(hash_get(ht, KW_OPT_SUBHDR));

	/* check if a function or more must be searched */
	obsolete_string_to_list(ht, KW_OPT_FUNCTION);
	funcs = po_get_list(hash_get(ht, KW_OPT_FUNCTION));
	if (funcs != NULL) {
		n = da_usize(funcs);
		for (i = 0 ; i < n ; i++) {
			pstr = da_idx(funcs, i);
			record_def_data(pgd->htab, pstr, NULL);
			record_def_adv(pgd->htab, TAG_TYPE_HDR_PRC, scb.header, pstr, NULL, NULL);
		}
	}

	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get language */
	lang = get_lang_str(ht, pgd);
	if (lang == NULL) {
		errorf("Failed, language has not been set.");
		return(false);
	}

	/* init build structure */
	if (set_language(&scb, lang) == false) {
		pmk_log("\tSkipped, unknown language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get the appropriate compiler */
	pstr = set_compiler(&scb, pgd->htab);
	if (pstr == NULL) {
		pmk_log("\tSkipped, cannot get compiler path for language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	pmk_log("\tUse %s language with %s compiler.\n", lang, pstr);

	/* check for alternative variable for CFLAGS */
	pstr = po_get_str(hash_get(ht, PMKVAL_ENV_CFLAGS));
	if (pstr != NULL) {
		/* init alternative variable */
		if (hash_get(pgd->htab, pstr) == NULL) {
			if (hash_update_dup(pgd->htab, pstr, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, pstr);
				return(false);
			}
		}

		scb.alt_cflags = pstr;
	}
	pmk_log("\tStore compiler flags in '%s'.\n", get_cflags_label(&scb));

	/* use each element of INC_PATH with -I */
	pstr = (char *) hash_get(pgd->htab, PMKCONF_PATH_INC);
	if (pstr == NULL) {
		errorf("%s not available.", PMKCONF_PATH_INC);
		return(false);
	}

	if (get_file_dir_path(scb.header, pstr, inc_path, sizeof(inc_path)) == true) {
		pstr = strdup(inc_path);
		if (pstr == NULL) {
			errorf(ERRMSG_MEM);
			return(false);
		}
		strlcpy(inc_path, "-I", sizeof(inc_path)); /* no check */
		if (strlcat_b(inc_path, pstr, sizeof(inc_path)) == false) {
			errorf("failed to add '%s' in include path.", inc_path);
			return(false);
		}
	} else {
		/* include not found, init inc_path with "" */
		if (strlcpy_b(inc_path, "", sizeof(inc_path)) == false) {
			errorf("failed to initialise include path.");
			return(false);
		}
	}
	set_cflags(&scb, inc_path);

	/*
		check header file
	*/
	pmk_log("\tFound header '%s' : ", scb.header);

	/* build test source file */
	if (code_builder(&scb) == false) {
		errorf("cannot build test file.");
		return(false);
	}

	/* build compiler command */
	 if (cmdline_builder(&scb, LINK_SRC) == false) {
		errorf(ERR_MSG_CC_CMD);
		return(false);
	}

	/* launch build and get result */
	rslt = object_builder(&scb);

	/* clean files */
	cb_cleaner(&scb);

	/* if result is false and dependency headers are provided */
	if ((rslt == false) && (shdrs != NULL)) {
		/* output result of previous test */
		pmk_log("no.\n");

		/*
			check header file with sub headers
		*/
		pmk_log("\tFound header '%s' using dependency headers : ", scb.header);

		scb.subhdrs = shdrs;

		/* build test source file */
		if (code_builder(&scb) == false) {
			errorf("cannot build test file.");
			return(false);
		}

		/* build compiler command */
		 if (cmdline_builder(&scb, LINK_SRC) == false) {
			errorf(ERR_MSG_CC_CMD);
			return(false);
		}

		/* launch build and get result */
		rslt = object_builder(&scb);

		/* clean files */
		cb_cleaner(&scb);

		/* XXX TODO set sub header flag ? */
	}

	/* process result */
	if (rslt == false) {
		pmk_log("no.\n");
		return(process_required(pgd, cmd, required, NULL, NULL));
	}
	pmk_log("yes.\n");
	/* define for template */
	record_def_data(pgd->htab, scb.header, DEFINE_DEFAULT);
	record_def_adv(pgd->htab, TAG_TYPE_HDR, scb.header, NULL, NULL, DEFINE_DEFAULT);

	/*
		check macros in header file
	*/
	if (macros != NULL) {
		while ((target = da_shift(macros)) && (target != NULL)) {
			/* init rbis */
			rbis = false;

			/* if header is okay */
			pmk_log("\tFound macro '%s' : ", target);

			scb.define = target;

			/* fill test file */
			if (code_builder(&scb) == false) {
				errorf("cannot build test file.");
				return(false);
			}

			/* build compiler command */
			 if (cmdline_builder(&scb, LINK_SRC) == false) {
				errorf(ERR_MSG_CC_CMD);
				return(false);
			}

			/* launch build and get result */
			rbis = object_builder(&scb);

			/* clean files */
			cb_cleaner(&scb);

			/* process result */
			if (rbis == true) {
				pmk_log("yes.\n");
				/* define for template */
				record_def_data(pgd->htab, target, DEFINE_DEFAULT);
				record_def_adv(pgd->htab, TAG_TYPE_HDR_MCR, scb.header, target, NULL, DEFINE_DEFAULT);
			} else {
				pmk_log("no.\n");
				rslt = false;
			}
		}

		/* reset define */
		scb.define = NULL;
	}

	/*
		check functions in header file
	*/
	if (funcs != NULL) {
		while ((target = da_shift(funcs)) && (target != NULL)) {
			/* test each function */
			pmk_log("\tFound function '%s' : ", target);

			scb.procedure = target;

			/* fill test file */
			if (code_builder(&scb) == false) {
				errorf("cannot build test file.");
				return(false);
			}

			 if (cmdline_builder(&scb, LINK_SRC) == false) {
				errorf(ERR_MSG_CC_CMD);
				return(false);
			}

			/* launch build and get result */
			rbis = object_builder(&scb);

			/* clean files */
			cb_cleaner(&scb);

			/* process result */
			if (rbis == true) {
				pmk_log("yes.\n");

				/* define for template */
				record_def_data(pgd->htab, target, DEFINE_DEFAULT);
				record_def_adv(pgd->htab, TAG_TYPE_HDR_PRC, scb.header, target, NULL, DEFINE_DEFAULT);
			} else {
				pmk_log("no.\n");
				rslt = false;
			}
		}
	}

	if (rslt == true) {
		label_set(pgd->labl, cmd->label, true);
		/* process additional defines */
		if (process_def_list(pgd->htab, defs, true) == false) {
			return(false);
		}

		/* put result in CFLAGS, CXXFLAGS or alternative variable */
		if (single_append(pgd->htab, get_cflags_label(&scb), strdup(inc_path)) == false) {
			errorf("failed to append '%s' in '%s'.", inc_path, get_cflags_label(&scb));
			return(false);
		}

		rval = true;
	} else {
		rval = process_required(pgd, cmd, required, NULL, NULL);
	}

	return(rval);
}


/*******************
 * pmk_check_lib() *
 ***********************************************************************
 DESCR
	check library
 ***********************************************************************/

bool pmk_check_lib(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool		 required,
				 rbis,
				 rslt = true,
				 rval;
	char		 lib_buf[TMP_BUF_LEN] = "",
				 lib_path[TMP_BUF_LEN] = "",
				*lang,
				 pattern[TMP_BUF_LEN] = "",
				*pstr,
				*target = NULL;
	code_bld_t	 scb;
	dynary		*da,
				*funcs,
				*defs;
	int			 i,
				 n;

	pmk_log("\n* Checking library [%s]\n", cmd->label);

	code_bld_init(&scb, pgd->buildlog);

	required = require_check(ht);

	pstr = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (pstr == NULL) {
		errorf("NAME not assigned in label '%s'.", cmd->label);
		return(false);
	}
	scb.library = pstr;
	record_def_adv(pgd->htab, TAG_TYPE_LIB, scb.library, NULL, NULL, NULL);

	/* check if a function or more must be searched */
	obsolete_string_to_list(ht, KW_OPT_FUNCTION);
	funcs = po_get_list(hash_get(ht, KW_OPT_FUNCTION));
	if (funcs != NULL) {
		n = da_usize(funcs);
		for (i = 0 ; i < n ; i++) {
			pstr = da_idx(funcs, i);
			record_def_data(pgd->htab, pstr, NULL);
			record_def_adv(pgd->htab, TAG_TYPE_LIB_PRC, scb.library, pstr, NULL, NULL);
		}
	}

	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get language */
	lang = get_lang_str(ht, pgd);
	if (lang == NULL) {
		errorf("Failed, language has not been set.");
		return(false);
	}

	/* init build structure */
	if (set_language(&scb, lang) == false) {
		pmk_log("\tSkipped, unknown language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get the appropriate compiler */
	pstr = set_compiler(&scb, pgd->htab);
	if (pstr == NULL) {
		pmk_log("\tSkipped, cannot get compiler path for language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	pmk_log("\tUse %s language with %s compiler.\n", lang, pstr);

	if (rslt == true) {
		/* check for alternative variable for LIBS */
		pstr = po_get_str(hash_get(ht, KW_OPT_LIBS));
		if (pstr != NULL) {
			/* init alternative variable */
			if (hash_get(pgd->htab, pstr) == NULL) {
				if (hash_update_dup(pgd->htab, pstr, "") == HASH_ADD_FAIL) {
					errorf(HASH_ERR_UPDT_ARG, pstr);
					return(false);
				}
			}

			scb.alt_libs = pstr;
		}
		pmk_log("\tStore library flags in '%s'.\n", get_libs_label(&scb));

		/* get actual content of LIBS, no need to check as it is initialised */
		set_cflags(&scb, hash_get(pgd->htab, PMKVAL_ENV_LIBS));
	}

	/* get the list of library path */
	pstr = (char *) hash_get(pgd->htab, PMKCONF_PATH_LIB);
	if (pstr == NULL) {
		errorf("%s not available.", PMKCONF_PATH_LIB);
		return(false);
	}

	/* convert to dynary */
	da = str_to_dynary(pstr, PATH_STR_DELIMITER);
	if (da == NULL) {
		errorf("unable to convert '%s'",PMKCONF_PATH_LIB);
		return(false);
	}

	/* generate library pattern */
	snprintf(pattern, sizeof(pattern), "lib%s*.*", scb.library);

	/* parse list of path to find the pattern */
	if (find_pattern(da, pattern, lib_buf, sizeof(lib_buf)) == true) {
		snprintf(lib_path, sizeof(lib_path), "-L%s", lib_buf);
		set_ldflags(&scb, lib_path);
	}

	/* clean dynary now useless */
	da_destroy(da);
	
	/*
		check library
	*/
	pmk_log("\tFound library '%s' : ", scb.library);

	/* build test source file */
	if (code_builder(&scb) == false) {
		errorf("cannot build test file.");
		return(false);
	}

	/* build compiler command */
	 if (cmdline_builder(&scb, LINK_SRC) == false) {
		errorf(ERR_MSG_CC_CMD);
		return(false);
	}

	/* launch build and get result */
	rslt = object_builder(&scb);

	/* clean files */
	cb_cleaner(&scb);

	/* process result */
	if (rslt == false) {
		pmk_log("no.\n");
		return(process_required(pgd, cmd, required, NULL, NULL));
	}
	pmk_log("yes.\n");
	/* define for template */
	record_def_data(pgd->htab, scb.library, DEFINE_DEFAULT);
	record_def_adv(pgd->htab, TAG_TYPE_LIB, scb.library, pstr, NULL, DEFINE_DEFAULT);

	/*
		check functions
	*/

	if (funcs != NULL) {
		while ((target = da_shift(funcs)) && (target != NULL)) {
			/* test each function */
			pmk_log("\tFound function '%s' : ", target);

			scb.procedure = target;

			/* build test source file */
			if (code_builder(&scb) == false) {
				errorf("cannot build test file.");
				return(false);
			}

			/* build compiler command */
			 if (cmdline_builder(&scb, LINK_SRC) == false) {
				errorf(ERR_MSG_CC_CMD);
				return(false);
			}

			/* launch build and get result */
			rbis = object_builder(&scb);

			/* clean files */
			cb_cleaner(&scb);

			/* process result */
			if (rbis == true) {
				pmk_log("yes.\n");

				/* define for template */
				record_def_data(pgd->htab, target, DEFINE_DEFAULT);
				record_def_adv(pgd->htab, TAG_TYPE_LIB_PRC, scb.library, target, NULL, DEFINE_DEFAULT);
			} else {
				pmk_log("no.\n");
				rslt = false;
			}
		}
	}

	if (rslt == true) {
		label_set(pgd->labl, cmd->label, true);
		/* process additional defines */
		if (process_def_list(pgd->htab, defs, true) == false) {
			return(false);
		}

		if (scb.ldflags != NULL) {
			if (snprintf_b(lib_buf, sizeof(lib_buf), "%s -l%s", scb.ldflags, scb.library) == false) {
				errorf("failed to build library path or name.");
				return(false);
			}
		} else {
			if (snprintf_b(lib_buf, sizeof(lib_buf), "-l%s", scb.library) == false) {
				errorf("failed to build library name.");
				return(false);
			}
		}

		/* put result in LIBS or alternative variable */
		if (single_append(pgd->htab, get_libs_label(&scb), strdup(lib_buf)) == false) {
			errorf("failed to append '%s' in '%s'.", lib_buf, get_libs_label(&scb));
			return(false);
		}

		rval = true;
	} else {
		rval = process_required(pgd, cmd, required, NULL, NULL);
	}

	return(rval);
}


/**********************
 * pmk_check_config() *
 ***********************************************************************
 DESCR
	check with *-config utility
 ***********************************************************************/

bool pmk_check_config(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool		 required = true,
				 rval = false;
	char		 pipebuf[TMP_BUF_LEN],
				 cfgpath[MAXPATHLEN],
				*bpath,
				*cfgtool,
				*cflags,
				*lang,
				*libs,
				*libvers,
				*modname,
				*opt,
				*varname,
				*vtmp;
	code_bld_t	 scb;
	dynary		*defs;
	cfgtcell	*pcc = NULL;

	pmk_log("\n* Checking with config tool [%s]\n", cmd->label);

	code_bld_init(&scb, pgd->buildlog);
	
	required = require_check(ht);

	cfgtool = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (cfgtool == NULL) {
		errorf("NAME not assigned in label '%s'.", cmd->label);
		return(false);
	}
	record_def_adv(pgd->htab, TAG_TYPE_CFGTOOL, cfgtool, NULL, NULL, NULL);

	/* check dependencies */
	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, cfgtool, NULL));
	}

	/* check if a module name is given */
	modname = po_get_str(hash_get(ht, KW_OPT_MODULE));

	/* check if a variable name is given */
	varname = po_get_str(hash_get(ht, KW_OPT_VARIABLE));
	if (varname == NULL) {
		vtmp = conv_to_tag(cfgtool);
		if (vtmp == NULL) {
			errorf("VARIABLE not assigned in label '%s'.", cmd->label);
			return(false);
		}
		/* if not then use default naming scheme */
		varname = strdup(vtmp);
		if (varname == NULL) {
			errorf(ERRMSG_MEM);
			return(false);
		}
	}

	bpath = hash_get(pgd->htab, PMKCONF_PATH_BIN);
	if (bpath == NULL) {
		errorf("%s not available.", PMKCONF_PATH_BIN);
		return(false);
	}

	/* get language */
	lang = get_lang_str(ht, pgd);
	if (lang == NULL) {
		errorf("Failed, language has not been set.");
		return(false);
	}

	/* init build structure */
	if (set_language(&scb, lang) == false) {
		pmk_log("\tSkipped, unknown language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	/* check for alternative variable for CFLAGS */
	cflags = po_get_str(hash_get(ht, PMKVAL_ENV_CFLAGS));
	if (cflags != NULL) {
		/* init alternative variable */
		if (hash_get(pgd->htab, cflags) == NULL) {
			if (hash_update_dup(pgd->htab, cflags, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, cflags);
				return(false);
			}
		}
	} else {
		/* use default variable of the used language */
		cflags = get_cflags_label(&scb);
	}

	/* check for alternative variable for LIBS */
	libs = po_get_str(hash_get(ht, KW_OPT_LIBS));
	if (libs != NULL) {
		/* init alternative variable */
		if (hash_get(pgd->htab, libs) == NULL) {
			if (hash_update_dup(pgd->htab, libs, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, libs);
				return(false);
			}
		}
	} else {
		/* use default library variable */
		libs = PMKVAL_ENV_LIBS;
	}

	/* try to locate cfgtool */
	pmk_log("\tFound config tool '%s' : ", cfgtool);
	if (get_file_path(cfgtool, bpath, cfgpath, sizeof(cfgpath)) == false) {
		pmk_log("no.\n");
		rval = process_required(pgd, cmd, required, cfgtool, NULL);
		if (rval == true) {
			/* set path as empty for the key given by varname */
			if (hash_update_dup(pgd->htab, varname, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, varname);
				return(false);
			}
		}
		return(rval);
	} else {
		pmk_log("yes.\n");
		/* recording path of config tool under the key given by varname */
		if (hash_update_dup(pgd->htab, varname, cfgpath) == HASH_ADD_FAIL) {
			errorf(HASH_ERR_UPDT_ARG, varname);
			return(false);
		}
	}

	/* check if config tool data is loaded */
	if (check_cfgt_data(pgd) == false) {
		errorf("unable to load config tool data.");
		return(false);
	}

	/* check if specific tool option exists */
	pmk_log("\tUse specific options : ");
	pcc = cfgtcell_get_cell(pgd->cfgt, cfgtool);
	if (pcc != NULL) {
		pmk_log("yes\n");
	} else {
		pmk_log("no\n");
	}

	libvers = po_get_str(hash_get(ht, KW_OPT_VERSION));

	/* if VERSION is provided then check it */
	if (libvers != NULL) {
		/* check if specific option exists */
		if ((pcc != NULL) && (pcc->version != NULL)) {
			opt = pcc->version;
		} else {
			opt = CFGTOOL_OPT_VERSION;
		}

		if (ct_get_version(cfgpath, opt, pipebuf, sizeof(pipebuf)) == false) {
			errorf("cannot get version from '%s'.", cfgpath);
			return(false);
		} else {
			pmk_log("\tFound version >= %s : ", libvers);

			if (compare_version(libvers, pipebuf) < 0) {
				/* version does not match */
				pmk_log("no (%s).\n", pipebuf);
				return(process_required(pgd, cmd, required, cfgtool, NULL));
			} else {
				pmk_log("yes (%s).\n", pipebuf);
			}
		}
	}

	/* record gathered data */
	record_def_data(pgd->htab, cfgtool, DEFINE_DEFAULT);
	record_def_adv(pgd->htab, TAG_TYPE_CFGTOOL, cfgtool, NULL, NULL, DEFINE_DEFAULT);
	label_set(pgd->labl, cmd->label, true);
	/* process additional defines */
	if (process_def_list(pgd->htab, defs, true) == false) {
		return(false);
	}

	/* check if specific option exists */
	if ((pcc != NULL) && (pcc->cflags != NULL)) {
		opt = pcc->cflags;
	} else {
		opt = CFGTOOL_OPT_CFLAGS;
	}

	if (ct_get_data(cfgpath, opt, modname, pipebuf, sizeof(pipebuf)) == false) {
		errorf("cannot get CFLAGS.");
		return(false);
	} else {
		/* put result in CFLAGS, CXXFLAGS or alternative variable */
		if (single_append(pgd->htab, cflags, strdup(pipebuf)) == false) {
			errorf("failed to append '%s' in '%s'.", pipebuf, cflags);
			return(false);
		} else {
			pmk_log("\tStored compiler flags in '%s'.\n", cflags);
		}
	}

	/* check if specific option exists */
	if ((pcc != NULL) && (pcc->libs != NULL)) {
		opt = pcc->libs;
	} else {
		opt = CFGTOOL_OPT_LIBS;
	}

	if (ct_get_data(cfgpath, opt, "", pipebuf, sizeof(pipebuf)) == false) {
		errorf("cannot get LIBS.");
		return(false);
	} else {
		/* put result in LIBS or alternative variable */
		if (single_append(pgd->htab, libs, strdup(pipebuf)) == false) {
			errorf("failed to append '%s' in '%s'.", pipebuf, libs);
			return(false);
		} else {
			pmk_log("\tStored library flags in '%s'.\n", libs);
		}
	}

	return(true);
}


/**************************
 * pmk_check_pkg_config() *
 ***********************************************************************
 DESCR
	check pkg-config module using internal support
 ***********************************************************************/

bool pmk_check_pkg_config(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool		 required = true;
	char		 pc_cmd[MAXPATHLEN],
				 pc_buf[MAXPATHLEN],
				*bpath,
				*cflags,
				*lang,
				*libs,
				*libvers,
				*pc_path,
				*pipebuf,
				*pstr,
				*target;
	code_bld_t	 scb;
	dynary		*defs;
	pkgcell		*ppc;
	pkgdata		*ppd;

	pmk_log("\n* Checking pkg-config module [%s]\n", cmd->label);

	code_bld_init(&scb, pgd->buildlog);

	required = require_check(ht);

	target = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (target == NULL) {
		errorf("NAME not assigned in label '%s'.", cmd->label);
		return(false);
	}
	record_def_adv(pgd->htab, TAG_TYPE_PKGCFG, target, NULL, NULL, NULL);

	/* check dependencies */
	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, target, NULL));
	}

	/* try to get pkg-config lib path from pmk.conf */
	pstr = hash_get(pgd->htab, PMKCONF_PC_PATH_LIB);
	if (pstr == NULL) {
		pmk_log("\tUnable to get %s from %s.\n",
			PMKCONF_PC_PATH_LIB, PREMAKE_CONFIG_PATH);
		return(false);
	}

	pc_path = process_string(pstr, pgd->htab);
	if (pc_path == NULL) {
		pmk_log("\tUnable to find pkg-config libdir.\n");
		pmk_log("\tWARNING : pkg-config may not be installed\n");
		pmk_log("\t or pmk.conf need to be updated.\n");
		return(false);
	}

	/* get language */
	lang = get_lang_str(ht, pgd);
	if (lang == NULL) {
		errorf("Failed, language has not been set.");
		return(false);
	}

	/* init build structure */
	if (set_language(&scb, lang) == false) {
		pmk_log("\tSkipped, unknown language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	/* check for alternative variable for CFLAGS */
	cflags = po_get_str(hash_get(ht, PMKVAL_ENV_CFLAGS));
	if (cflags != NULL) {
		/* init alternative variable */
		if (hash_get(pgd->htab, cflags) == NULL) {
			if (hash_update_dup(pgd->htab, cflags, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, cflags);
				return(false);
			}
		}
	} else {
		/* use default variable of the used language */
		cflags = get_cflags_label(&scb);
	}

	/* check for alternative variable for LIBS */
	libs = po_get_str(hash_get(ht, KW_OPT_LIBS));
	if (libs != NULL) {
		/* init alternative variable */
		if (hash_get(pgd->htab, libs) == NULL) {
			if (hash_update_dup(pgd->htab, libs, "") == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, libs);
				return(false);
			}
		}
	} else {
		/* use default library variable */
		libs = PMKVAL_ENV_LIBS;
	}

	ppd = pkgdata_init();
	if (ppd == NULL) {
		errorf("cannot init pkgdata.");
		return(false);
	}

	/* collect packages data */
	if (pkg_collect(pc_path, ppd) == false) {
		pkgdata_destroy(ppd);
		errorf("cannot collect packages data");
		return(false);
	}

	/* check if package exists */
	pmk_log("\tFound package '%s' : ", target);
	if (pkg_mod_exists(ppd, target) == false) {
		pkgdata_destroy(ppd);
		pmk_log("no.\n");

		/* get binary path */
		bpath = hash_get(pgd->htab, PMKCONF_PATH_BIN);
		if (bpath == NULL) {
		        errorf("%s not available.", PMKCONF_PATH_BIN);
			return(false);
		}

		/* check if config tool data is loaded */
		if (check_cfgt_data(pgd) == false) {
			errorf("unable to load config tool data.");
			return(false);
		}

		/* set config tool filename */
		if (cfgtcell_get_binary(pgd->cfgt, target, pc_cmd, sizeof(pc_cmd)) == false) {
			if (snprintf_b(pc_cmd, sizeof(pc_cmd), "%s-config", target) == false) {
				errorf("overflow in snprintf().");
				return(false);
			}
		}

		/* looking for it in the path */
		if (get_file_path(pc_cmd, bpath, pc_buf, sizeof(pc_buf)) == true) {
			/* use CHECK_CONFIG */
			pmk_log("\tFound alternative '%s' tool.\n", pc_cmd);

			/* override NAME to use divert on CHECK_CONFIG */
			hash_update(ht, KW_OPT_NAME, po_mk_str(pc_cmd));
			pmk_log("\tWARNING: rerouting to CHECK_CONFIG\n");
			pmk_log("\tPlease consider using directly CHECK_CONFIG with '%s'\n", pc_cmd);

			/* call pmk_check_config with the config tool */
			return(pmk_check_config(cmd, ht, pgd));
		}

		return(process_required(pgd, cmd, required, target, NULL));
	} else {
		pmk_log("yes.\n");
	}

	libvers = po_get_str(hash_get(ht, KW_OPT_VERSION));
	if (libvers != NULL) {
		/* if VERSION is provided then check it */
		ppc = pkg_cell_add(ppd, target);
		if (ppc == NULL) {
			pkgdata_destroy(ppd);
			errorf("cannot get version.");
			return(false);
		} else {
			pmk_log("\tFound version >= %s : ", libvers);

			pipebuf = ppc->version;
			if (compare_version(libvers, pipebuf) < 0) {
				/* version does not match */
				pmk_log("no (%s).\n", pipebuf);

				pkgdata_destroy(ppd);

				return(process_required(pgd, cmd, required, target, NULL));
			} else {
				pmk_log("yes (%s).\n", pipebuf);
			}
		}
	}

	/* gather data */
	if (pkg_recurse(ppd, target) == false) {
		pkgdata_destroy(ppd);
		errorf("failed to gather packages data (pkg_recurse() function call)");
		return(false);
	}

	/* record gathered data */
	record_def_data(pgd->htab, target, DEFINE_DEFAULT);
	record_def_adv(pgd->htab, TAG_TYPE_PKGCFG, target, NULL, NULL, DEFINE_DEFAULT);
	label_set(pgd->labl, cmd->label, true);
	/* process additional defines */
	if (process_def_list(pgd->htab, defs, true) == false) {
		return(false);
	}

	/* get cflags recursively */
	pipebuf = pkg_get_cflags(ppd);
	if (pipebuf == NULL) {
		pkgdata_destroy(ppd);
		errorf("cannot get CFLAGS.");
		return(false);
	} else {
		/* put result in CFLAGS, CXXFLAGS or alternative variable */
		if (single_append(pgd->htab, cflags, pipebuf) == false) {
			pkgdata_destroy(ppd);
			errorf("failed to append '%s' in '%s'.", pipebuf, cflags);
			return(false);
		} else {
			pmk_log("\tStored compiler flags in '%s'.\n", cflags);
		}
	}

	/* get libs recursively */
	pipebuf = pkg_get_libs(ppd);
	if (pipebuf == NULL) {
		pkgdata_destroy(ppd);
		errorf("cannot get LIBS.");
		return(false);
	} else {
		/* put result in LIBS or alternative variable */
		if (single_append(pgd->htab, libs, pipebuf) == false) {
			pkgdata_destroy(ppd);
			errorf("failed to append '%s' in '%s'.", pipebuf, libs);
			return(false);
		} else {
			pmk_log("\tStored library flags in '%s'.\n", libs);
		}
	}

	return(true);
}


/********************
 * pmk_check_type() *
 ***********************************************************************
 DESCR
	check type
 ***********************************************************************/

bool pmk_check_type(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool		 required,
				 rslt = true,
				 rval;
	char		 inc_path[MAXPATHLEN] = "",
				*type,
				*member,
				*lang,
				*pstr;
	code_bld_t	 scb;
	dynary		*defs;

	pmk_log("\n* Checking type [%s]\n", cmd->label);

	code_bld_init(&scb, pgd->buildlog);

	required = require_check(ht);

	/* get type name */
	type = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (type == NULL) {
		errorf("%s not assigned in label '%s'", KW_OPT_NAME, cmd->label);
		return(false);
	}
	record_def_data(pgd->htab, type, NULL);
	record_def_adv(pgd->htab, TAG_TYPE_TYPE, type, NULL, NULL, NULL);

	/* check if an header must be used */
	scb.header = po_get_str(hash_get(ht, KW_OPT_HEADER));
	if (scb.header != NULL) {
		record_def_data(pgd->htab, scb.header, NULL);
	}

	/* check if a structure member is given */
	member = po_get_str(hash_get(ht, KW_OPT_MEMBER));
	if (member != NULL) {
		record_def_data(pgd->htab, member, NULL);
	}

	if (scb.header != NULL) {
		record_def_adv(pgd->htab, TAG_TYPE_HDR_TYPE, scb.header, type, NULL, NULL);
		if (member != NULL) {
			record_def_adv(pgd->htab, TAG_TYPE_HDR_TYP_MBR, scb.header, type, member, NULL);
		}
	} else {
		if (member != NULL) {
			record_def_adv(pgd->htab, TAG_TYPE_TYP_MBR, type, member, NULL, NULL);
		}
	}


	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get language */
	lang = get_lang_str(ht, pgd);
	if (lang == NULL) {
		errorf("Failed, language has not been set.");
		return(false);
	}

	/* init build structure */
	if (set_language(&scb, lang) == false) {
		pmk_log("\tSkipped, unknown language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	/* get the appropriate compiler */
	pstr = set_compiler(&scb, pgd->htab);
	if (pstr == NULL) {
		pmk_log("\tSkipped, cannot get compiler path for language '%s'.\n", lang);
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	pmk_log("\tUse %s language with %s compiler.\n", lang, pstr);

	/* check optional header */
	if (scb.header != NULL) {
		/* use each element of INC_PATH with -I */
		pstr = (char *) hash_get(pgd->htab, PMKCONF_PATH_INC);
		if (pstr == NULL) {
			errorf("%s not available.", PMKCONF_PATH_INC);
			return(false);
		}

		if (get_file_dir_path(scb.header, pstr, inc_path, sizeof(inc_path)) == true) {
			pstr = strdup(inc_path);
			if (pstr == NULL) {
				errorf(ERRMSG_MEM);
				return(false);
			}
			strlcpy(inc_path, "-I", sizeof(inc_path)); /* no check */
			if (strlcat_b(inc_path, pstr, sizeof(inc_path)) == false) {
				errorf("failed to add '%s' in include path.", inc_path);
				return(false);
			}
		} else {
			/* include not found, init inc_path with "" */
			if (strlcpy_b(inc_path, "", sizeof(inc_path)) == false) {
				errorf("failed to initialise include path.");
				return(false);
			}
		}
		set_cflags(&scb, inc_path);

		/*
			check header file
		*/
		pmk_log("\tFound header '%s' : ", scb.header);

		/* build test source file */
		if (code_builder(&scb) == false) {
			errorf("cannot build test file.");
			return(false);
		}

		/* build compiler command */
		 if (cmdline_builder(&scb, LINK_SRC) == false) {
			errorf(ERR_MSG_CC_CMD);
			return(false);
		}

		/* launch build and get result */
		rslt = object_builder(&scb);

		/* clean files */
		cb_cleaner(&scb);

		/* process result */
		if (rslt == false) {
			pmk_log("no.\n");
			return(process_required(pgd, cmd, required, NULL, NULL));
		}

		pmk_log("yes.\n");
		/* define for template */
		record_def_data(pgd->htab, scb.header, DEFINE_DEFAULT);
		record_def_adv(pgd->htab, TAG_TYPE_HDR_TYPE, scb.header, type, NULL, DEFINE_DEFAULT);
	}

	scb.type = type;

	pmk_log("\tFound type '%s' : ", scb.type);

	/* build test source file */
	if (code_builder(&scb) == false) {
		errorf("cannot build test file.");
		return(false);
	}

	/* build compiler command */
	 if (cmdline_builder(&scb, LINK_SRC) == false) {
		errorf(ERR_MSG_CC_CMD);
		return(false);
	}

	/* launch build and get result */
	rslt = object_builder(&scb);

	/* clean files */
	cb_cleaner(&scb);

	/* process result */
	if (rslt == false) {
		pmk_log("no.\n");
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	pmk_log("yes.\n");

	/* define for template */
	record_def_data(pgd->htab, type, DEFINE_DEFAULT);
	record_def_adv(pgd->htab, TAG_TYPE_TYPE, type, NULL, NULL, DEFINE_DEFAULT);

	/* check optional member */
	if (member != NULL) {
		scb.member = member;

		pmk_log("\tFound member '%s' : ", scb.member);

		/* build test source file */
		if (code_builder(&scb) == false) {
			errorf("cannot build test file.");
			return(false);
		}

		/* build compiler command */
		 if (cmdline_builder(&scb, LINK_SRC) == false) {
			errorf(ERR_MSG_CC_CMD);
			return(false);
		}

		/* clean files */
		cb_cleaner(&scb);

		/* process result */
		if (rslt == false) {
			pmk_log("no.\n");
			return(process_required(pgd, cmd, required, NULL, NULL));
		}

		pmk_log("yes.\n");

		/* define for template */
		record_def_data(pgd->htab, member, DEFINE_DEFAULT);
		record_def_adv(pgd->htab, TAG_TYPE_HDR_TYPE, type, member, NULL, DEFINE_DEFAULT);
		if (scb.header != NULL) {
			record_def_adv(pgd->htab, TAG_TYPE_HDR_TYP_MBR, scb.header, type, member, DEFINE_DEFAULT);
		}
	}

	if (rslt == true) {
		label_set(pgd->labl, cmd->label, true);
		/* process additional defines */
		if (process_def_list(pgd->htab, defs, true) == false) {
			return(false);
		}

		rval = true;
	} else {
		rval = process_required(pgd, cmd, required, scb.type, NULL);
	}

	return(rval);
}


/************************
 * pmk_check_variable() *
 ***********************************************************************
 DESCR
	check if variable exists and optionally it's value
 ***********************************************************************/

bool pmk_check_variable(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool	 required,
			 rval = false;
	char	*var,
			*value,
			*varval;
	dynary	*defs;

	pmk_log("\n* Checking variable [%s]\n", cmd->label);

	required = require_check(ht);

	var = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (var == NULL) {
		errorf("NAME not assigned in label '%s'", cmd->label);
		return(false);
	}

	/* look for additional defines */
	defs = po_get_list(hash_get(ht, KW_OPT_DEFS));
	if (process_def_list(pgd->htab, defs, false) == false) {
		return(false);
	}

	if (depend_check(ht, pgd) == false) {
		pmk_log("\t%s\n", pgd->errmsg);
		return(process_required(pgd, cmd, required, var, NULL));
	}

	pmk_log("\tFound variable '%s' : ", var);

	/* trying to get variable */
	varval = hash_get(pgd->htab, var);
	if (varval != NULL) {
		pmk_log("yes.\n");

		value = po_get_str(hash_get(ht, KW_OPT_VALUE));
		if (value == NULL) {
			label_set(pgd->labl, cmd->label, true);
			/* process additional defines */
			if (process_def_list(pgd->htab, defs, true) == false) {
				return(false);
			}

			rval = true;
		} else {
			pmk_log("\tVariable match value '%s' : ", value);

			if (strncmp(value, varval, sizeof(varval)) == 0) {
				pmk_log("yes.\n");
				label_set(pgd->labl, cmd->label, true);
				if (process_def_list(pgd->htab, defs, true) == false) {
					return(false);
				}

				rval = true;
			} else {
				pmk_log("no.\n");
				rval = process_required(pgd, cmd, required, NULL, NULL);
				if (rval == false) {
					errorf("variable value does not match ('%s' != '%s').", value, varval);
				}
			}
		}
	} else {
		pmk_log("no.\n");
		rval = process_required(pgd, cmd, required, NULL, NULL);
		if (rval == false) {
			errorf("failed to find variable '%s'.", var);
		}
	}

	return(rval);
}


/************************
 * pmk_build_lib_name() *
 ***********************************************************************
 DESCR
	build names of a library
 ***********************************************************************/

bool pmk_build_lib_name(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	bool	 required,
			 versbool;
	char	*shvar = NULL,
			*stvar = NULL,
			*pstr,
			*value;
	pmkobj	*po;

	pmk_log("\n* Building library name\n");

	required = require_check(ht);
	
	pmk_log("\tShared library support : ");
	if (pgd->sys_detect == false) {
		pmk_log("no.\n");
		return(process_required(pgd, cmd, required, NULL, NULL));
	}

	pmk_log("yes.\n");

	pstr = hash_get(pgd->htab, SL_SYS_LABEL);
	pmk_log("\tUsing support for '%s'.\n", pstr);

	/* get name (REQUIRED) */
	pstr = po_get_str(hash_get(ht, KW_OPT_NAME));
	if (pstr == NULL) {
		errorf("NAME not assigned in label '%s'", cmd->label);
		return(false);
	}

#ifdef SHLIB_DEBUG
	debugf("pstr(name) = '%s'", pstr);
#endif
	value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
	debugf("value = '%s'", value);
#endif
	hash_update(pgd->htab, LIB_KW_NAME, value);

	/* get major version number */
	pstr = po_get_str(hash_get(ht, KW_OPT_MAJOR));
	if (pstr != NULL) {
#ifdef SHLIB_DEBUG
		debugf("pstr(major) = '%s'", pstr);
#endif
		value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
		debugf("value = '%s'", value);
#endif
		hash_update(pgd->htab, LIB_KW_MAJ, value); /* no dup */
	}

	/* get minor version number */
	pstr = po_get_str(hash_get(ht, KW_OPT_MINOR));
	if (pstr != NULL) {
#ifdef SHLIB_DEBUG
		debugf("pstr(minor) = '%s'", pstr);
#endif
		value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
		debugf("value = '%s'", value);
#endif
		hash_update(pgd->htab, LIB_KW_MIN, value); /* no dup */
	}

	/* get shared lib variable */
	pstr = po_get_str(hash_get(ht, KW_SL_SHARED));
	if (pstr != NULL) {
#ifdef SHLIB_DEBUG
		debugf("pstr(SHARED) = '%s'", pstr);
#endif
		shvar = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
		debugf("shvar = '%s'", shvar);
#endif
	}

	/* get static lib variable */
	pstr = po_get_str(hash_get(ht, KW_SL_STATIC));
	if (pstr != NULL) {
#ifdef SHLIB_DEBUG
		debugf("pstr(STATIC) = '%s'", pstr);
#endif
		stvar = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
		debugf("stvar = '%s'", stvar);
#endif
	}

	/* get versioning boolean */
	po = hash_get(ht, KW_SL_VERSION);
	if (po != NULL) {
		versbool = po_get_bool(po);
	} else {
		/* no version by default */
		versbool = false;
	}

	/* process shared lib name */
	if (shvar != NULL) {
		if (versbool == false) {
			/* get libname without version */
			pstr = hash_get(pgd->htab, LIB_KW_SH_NONE);
#ifdef SHLIB_DEBUG
			debugf("pstr(LIB_KW_SH_NONE) = '%s'", pstr);
#endif
			value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
			debugf("value = '%s'", value);
#endif
		} else {
			pstr = hash_get(pgd->htab, LIB_KW_SH_VERS);
#ifdef SHLIB_DEBUG
			debugf("pstr(LIB_KW_SH_VERS) = '%s'", pstr);
#endif
			value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
			debugf("value = '%s'", value);
#endif
		}

		/* no dup, no free */
		if (hash_update(pgd->htab, shvar, value) == HASH_ADD_FAIL) {
			errorf(HASH_ERR_UPDT_ARG, shvar);
			return(false);
		}
		pmk_log("\tSetting %s to '%s'\n", shvar, value);
#ifdef SHLIB_DEBUG
		debugf("save in '%s'", shvar);
#endif
		free(shvar);
	}

	/* process static lib name */
	if (stvar != NULL) {
		if (versbool == false) {
			/* get libname without version */
			pstr = hash_get(pgd->htab, LIB_KW_ST_NONE);
#ifdef SHLIB_DEBUG
			debugf("pstr(LIB_KW_ST_NONE) = '%s'", pstr);
#endif
			value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
			debugf("value = '%s'", value);
#endif
		} else {
			pstr = hash_get(pgd->htab, LIB_KW_ST_VERS);
#ifdef SHLIB_DEBUG
			debugf("pstr(LIB_KW_ST_VERS) = '%s'", pstr);
#endif
			value = process_string(pstr, pgd->htab);
#ifdef SHLIB_DEBUG
			debugf("value = '%s'", value);
#endif
		}

		/* no dup, no free */
		if (hash_update(pgd->htab, stvar, value) == HASH_ADD_FAIL) {
			errorf(HASH_ERR_UPDT_ARG, stvar);
			return(false);
		}
		pmk_log("\tSetting %s to '%s'\n", stvar, value);
#ifdef SHLIB_DEBUG
		debugf("save in '%s'", stvar);
#endif
		free(stvar);
	}

	return(true);
}


/**************************
 * pmk_build_shlib_name() *
 ***********************************************************************
 DESCR
	build name of a shared library
 ***********************************************************************/

bool pmk_build_shlib_name(pmkcmd *cmd, htable *ht, pmkdata *pgd) {
	pmk_log("\n* Building shared library name\n");

	pmk_log("\tBUILD_SHLIB_NAME() has been obsoleted by BUILD_LIB_NAME().\n");
	pmk_log("\tRead the man page for further information.\n");

	return(false);
}


/********************
 * option functions *
 ***********************************************************************
 * IN
 *	cmd : command structure
 *	popt : option structure
 *	pgd : global data
 *
 * OUT
 *	boolean
 ***********************************************************************/

/***********************
 * pmk_set_parameter() *
 ***********************************************************************
 DESCR
	set parameter
 ***********************************************************************/

bool pmk_set_parameter(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	/* gnu autoconf compatibility */
	if (strncmp(popt->key, KW_SETNGS_ACCOMP, sizeof(popt->key)) == 0) {
		return(pmk_setparam_accompat(cmd, popt, pgd));
	}

	/* global language */
	if (strncmp(popt->key, KW_SETNGS_GLANG, sizeof(popt->key)) == 0) {
		return(pmk_setparam_glang(cmd, popt, pgd));
	}

	/* set target files */
	if (strncmp(popt->key, KW_SETNGS_TARGET, sizeof(popt->key)) == 0) {
		return(pmk_setparam_target(cmd, popt, pgd));
	}

	/* compiler detection */
	if (strncmp(popt->key, KW_SETNGS_CCDTCT, sizeof(popt->key)) == 0) {
		return(pmk_setparam_detect(cmd, popt, pgd));
	}

	/* found unknown setting */
	pmk_log("\tunknown '%s' setting.\n", popt->key);
	return(false);
}


/***************************
 * pmk_setparam_accompat() *
 ***********************************************************************
 DESCR
	set autoconf compatability parameter
 ***********************************************************************/

bool pmk_setparam_accompat(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	char	*pstr;

	pmk_log("\tSetting autoconf compatibility :\n");

	/* XXX must check if valid
		pstr = (char *) hash_get(pgd->htab, "SYSCONFDIR");
		hash_update_dup(pgd->htab, "sysconfdir", pstr);
	*/

	/* if a file is given then it will be parsed later */
	pstr = po_get_str(popt->value);
	if (*pstr != CHAR_EOS) {
		pgd->ac_file = strdup(pstr);
		if (pgd->ac_file == NULL) {
			errorf(ERRMSG_MEM);
			return(false);
		}
		pmk_log("\t\tSet file to '%s'.\n", pstr);
		if (hash_update_dup(pgd->htab, AC_VAR_DEF, AC_VALUE_DEF) == HASH_ADD_FAIL) {
			errorf(HASH_ERR_UPDT_ARG, AC_VAR_DEF);
			return(false);
		}
		pmk_log("\t\tSet '%s' value to '%s'.\n", AC_VAR_DEF, AC_VALUE_DEF);
	}

	/* compatibility tags */
	if (ac_set_variables(pgd->htab) == false)
		return(false); /* XXX error message ? */
	pmk_log("\t\tSet specific variables.\n");

	return(true);
}


/************************
 * pmk_setparam_glang() *
 ***********************************************************************
 DESCR
	set global lang parameter
 ***********************************************************************/

bool pmk_setparam_glang(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	bool	 rval = false;
	char	*pstr;

	pmk_log("\tSetting global language :\n");

	/* set global language */
	pstr = po_get_str(popt->value);

	if (pstr != NULL) {
		/* check if provided lang is supported */
		if (verify_language(pstr) != LANG_UNKNOWN) {
			pgd->lang = strdup(pstr);
			if (pgd->lang == NULL) {
				errorf(ERRMSG_MEM);
				return(false);
			}
			pmk_log("\t\tSet to '%s'.\n", pstr);
			rval = true;
		} else {
			errorf("unknown language.");
		}
	} else {
		errorf("syntax error in LANG.");
	}

	return(rval);
}


/*************************
 * pmk_setparam_target() *
 ***********************************************************************
 DESCR
	set target list parameter
 ***********************************************************************/

bool pmk_setparam_target(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	dynary	*da;
	int		 i = 0,
			 n;

	pmk_log("\tCollecting targets :\n");

	da = po_get_list(popt->value);
	if (da == NULL) {
		errorf("syntax error in TARGET.");
		return(false);
	}

	n = da_usize(da);
	for (i=0 ; i < n ; i++) {
		pmk_log("\t\tAdded '%s'.\n", da_idx(da, i));
	}

	pgd->tlist = da;

	pmk_log("\t\tTotal %d target(s) added.\n", n);

	return(true);
}


/*************************
 * pmk_setparam_detect() *
 ***********************************************************************
 DESCR
	detect a list of compilers
 ***********************************************************************/

bool pmk_setparam_detect(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	char			*ccpath,
					*lang,
					*osname,
					*pstr,
					 temp[64]; /* XXX size */
	code_bld_t		 scb;
	comp_parse_t	*pcp;
	compiler_t		*pc;
	dynary			*da;
	hkeys			*phk;
	int				 i = 0,
					 n;

	pmk_log("\tDetecting compiler shared library support :\n");

	da = po_get_list(popt->value);
	if (da == NULL) {
		errorf("syntax error in DETECT.");
		return(false);
	}

	/* get os name */
	osname = hash_get(pgd->htab, PMKCONF_OS_NAME);

	/*
	 * parsing compiler data to build a database that will be used further
	 */
	pmk_log("\t\tGathering data for compiler detection.\n");
	pcp = parse_comp_file(PMKCOMP_DATA, osname);
	
	/* process each language provided in detection list */
	n = da_usize(da);
	for (i=0 ; i < n ; i++) {
		lang = da_idx(da, i);

		/* init code building structure */
		code_bld_init(&scb, pgd->buildlog);

		/* init build structure */
		if (set_language(&scb, lang) == false) {
			/*
			 * if language name is invalid then check
			 * for obsolete compiler name
			 */
			pstr = obsolete_get_lang_from_comp(lang); /* OBSOLETE */
			if (pstr == NULL) {
				errorf("Unknown language'%s'.\n", lang);
				return(false);
			}

			pmk_log("\t\tWARNING: obsolete value for compiler detection,\n");
			pmk_log("\t\t\tuse language label instead.\n");

			lang = pstr;
			if (set_language(&scb, lang) == false) {
				errorf("Unknown language '%s'.\n", lang);
				return(false);
			}
		}

		/* get the appropriate compiler */
		set_compiler(&scb, pgd->htab);
		pstr = get_compiler_label(&scb);
		ccpath = hash_get(pgd->htab, pstr);
		if (ccpath == NULL) {
			errorf("Cannot get compiler path ('%s').\n", pstr);
			return(false);
		}

		pmk_log("\t\tDetecting %s compiler : ", lang);

		/* try to identify the compiler */
		pc = &(pgd->comp_data.data[scb.lang]);
		if (comp_detect(ccpath, pgd->buildlog, pc, pcp, scb.pld->slcflags) == false) {
			pmk_log("failed.\n");
			return(false);
		}
		/* set the language type, so the compiler data are valid */
		pc->lang = scb.lang; /* XXX set in detect proc ? */

		pmk_log("%s (version %s).\n", pc->descr, pc->version);

		/* set shared lib compiler flags */
		pmk_log("\t\tSetting %s to '%s'\n", scb.pld->slcflags, pc->slcflags);
		if (hash_update_dup(pgd->htab, scb.pld->slcflags, pc->slcflags) == HASH_ADD_FAIL) {
			return(false);
		}

		/* set shared lib linker flags */
		pmk_log("\t\tSetting %s to '%s'\n", scb.pld->slldflags, pc->slldflags);
		if (hash_update_dup(pgd->htab, scb.pld->slldflags, pc->slldflags) == HASH_ADD_FAIL) {
			return(false);
		}

		/* try to compile shared object */
		pmk_log("\t\tChecking shared library support : ");
		if (check_so_support(&scb, pc->slcflags, pc->slldflags) == true) {
			pmk_log("ok.\n");

			/* shared lib support */
			snprintf(temp, sizeof(temp), "%s ", scb.pld->mk_bld_rule);
			if (hash_append(pgd->htab, MK_VAR_SL_BUILD, strdup(temp), NULL) == HASH_ADD_FAIL) {
				return(false);
			}
			snprintf(temp, sizeof(temp), "%s ", scb.pld->mk_cln_rule);
			if (hash_append(pgd->htab, MK_VAR_SL_CLEAN, strdup(temp), NULL) == HASH_ADD_FAIL) {
				return(false);
			}
			snprintf(temp, sizeof(temp), "%s ", scb.pld->mk_inst_rule);
			if (hash_append(pgd->htab, MK_VAR_SL_INST, strdup(temp), NULL) == HASH_ADD_FAIL) {
				return(false);
			}
			snprintf(temp, sizeof(temp), "%s ", scb.pld->mk_deinst_rule);
			if (hash_append(pgd->htab, MK_VAR_SL_DEINST, strdup(temp), NULL) == HASH_ADD_FAIL) {
				return(false);
			}
		} else {
			pmk_log("failed.\n");
		}

		/* clean cdata */
		cb_cleaner(&scb);
	}

	/* get system data */
	pmk_log("\t\tGetting system data for %s : ", osname);
	phk = hash_keys_sorted(pcp->sht);
	if (phk == NULL) {
		pmk_log("failed.\n");
	} else {
		for (i = 0 ; i < (int) phk->nkey ; i++) {
			pstr = hash_get(pcp->sht, phk->keys[i])	;
			hash_update_dup(pgd->htab, phk->keys[i], pstr); /* XXX check */
		}
		pmk_log("ok.\n");

		/* mark system as detected */
		pgd->sys_detect = true;
	}

	/* clean now useless parsed data */
	destroy_comp_parse(pcp);

	return(true);
}


/**********************
 * pmk_set_variable() *
 ***********************************************************************
 DESCR
	set variable
 ***********************************************************************/

bool pmk_set_variable(pmkcmd *cmd, prsopt *popt, pmkdata *pgd) {
	char	 buffer[TMP_BUF_LEN],
			*pstr,
			*value,
			*defname;
	int		 hval;

	/* XXX better way to do (specific hash for override)
	if (hash_get(pgd->htab, popt->key) == NULL) {
	*/
		/* process value string */
		pstr = po_get_str(popt->value);
		if (pstr == NULL) {
			errorf("bad value for '%s'.", popt->key);
			return(false);
		}
		value = process_string(pstr, pgd->htab);
		if (value != NULL) {
			hval = hash_update(pgd->htab, popt->key, value); /* no need to strdup */
			/* check return for message : defined or redefined */
			switch (hval) {
				case HASH_ADD_FAIL:
					errorf(HASH_ERR_UPDT_ARG, popt->key);
					return(false);
					break;

				case HASH_ADD_OKAY:
				case HASH_ADD_COLL:
					pmk_log("\tdefined");
					break;

				case HASH_ADD_UPDT:
					pmk_log("\tredefined");
					break;

			}
			/* remaining part of the message */
			pmk_log(" '%s' variable.\n", popt->key);

			/* store definition for autoconf compatibility */
			defname = gen_basic_tag_def(popt->key);
			if (defname == NULL) {
				errorf("unable to build define name for '%s'.", popt->key);
				return(false);
			}
			if (snprintf_b(buffer, sizeof(buffer),
					"#define %s \"%s\"", popt->key,
					value) == false) {
				errorf("buffer overflow for define value of '%s'.", popt->key);
				return(false);
			}
			if (hash_update_dup(pgd->htab, defname, buffer) == HASH_ADD_FAIL) {
				errorf(HASH_ERR_UPDT_ARG, defname);
				return(false);
			}

		} else {
			pmk_log("\tFailed processing of '%s'.\n", popt->key);
			return(false);
		}
	/*
	} else {
		pmk_log("\tSkipped '%s' define (overriden).\n", popt->key);
	}
	*/
	return(true);
}

/* vim: set noexpandtab tabstop=4 softtabstop=4 shiftwidth=4: */


syntax highlighted by Code2HTML, v. 0.9.1