/* $Id: pmkpc.c 1952 2007-02-15 19:01:17Z coudercd $ */

/*
 * Copyright (c) 2004-2005 Damien Couderc
 * Copyright (c) 2004 Xavier Santolaria <xavier@santolaria.net>
 * 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 <errno.h>
#include <stdlib.h>

#include "compat/pmk_stdio.h"
#include "compat/pmk_string.h"
#include "cfgtool.h"
#include "common.h"
#include "dynarray.h"
#include "hash_tools.h"
#include "parse.h"
#include "pkgconfig.h"
#include "pmkpc.h"
#include "premake.h"


/*#define PMKPC_DEBUG	1*/


extern char	*optarg;
extern int	 optind;


/**********
 variables
************************************************************************/

pcopt	pcoptions[] = {
		{"version",						false,	PMKPC_OPT_VERSION,				NULL},
		{"atleast-pkgconfig-version",	true,	PMKPC_OPT_ATLPKGVERS,			PC_USAGE_VERSION},
		{"exists",						false,	PMKPC_OPT_EXISTS,				NULL},
		{"list-all",					false,	PMKPC_OPT_LISTALL,				NULL},
		{"uninstalled",					false,	PMKPC_OPT_UNINST,				NULL},
		{"debug",						false,	PMKPC_OPT_DEBUG,				NULL},
		{"help",						false,	PMKPC_OPT_HELP,					NULL},
		{"usage",						false,	PMKPC_OPT_USAGE,				NULL},
		{"modversion",					false,	PMKPC_OPT_MODVERS,				NULL},
		{"atleast-version",				true,	PMKPC_OPT_ATLVERS,				PC_USAGE_VERSION},
		{"exact-version",				true,	PMKPC_OPT_EXTVERS,				PC_USAGE_VERSION},
		{"max-version",					true,	PMKPC_OPT_MAXVERS,				PC_USAGE_VERSION},
		{"cflags",						false,	PMKPC_OPT_CFLAGS,				NULL},
		{"cflags-only-I",				false,	PMKPC_OPT_CFLAGS_ONLY_PATH,		NULL},
		{"cflags-only-other",			false,	PMKPC_OPT_CFLAGS_ONLY_OTHER,	NULL},
		{"libs",						false,	PMKPC_OPT_LIBS, 				NULL},
		{"libs-only-l",					false,	PMKPC_OPT_LIBS_ONLY_LIB,		NULL},
		{"libs-only-L",					false,	PMKPC_OPT_LIBS_ONLY_PATH,		NULL},
		{"libs-only-other",				false,	PMKPC_OPT_LIBS_ONLY_OTHER,		NULL},
		{"variable",					true,	PMKPC_OPT_VAR,					PC_USAGE_VARNAME},
		{"define-variable",				true,	PMKPC_OPT_VAR_DEF,				PC_USAGE_VARVAL},
		{"print-errors",				false,	PMKPC_OPT_VAR_PRNT,				NULL},
		{"silence-errors",				false,	PMKPC_OPT_VAR_SILC,				NULL},
		{"errors-to-stdout",			false,	PMKPC_OPT_VAR_STDO,				NULL},
};
size_t	nbpcopt = sizeof(pcoptions) / sizeof(pcopt);


/**********
 functions
************************************************************************/

/***************
 optcell_init()

 DESCR
	init optcell structure

 IN
	-

 OUT
	optcell structure
************************************************************************/

optcell *optcell_init(void) {
	optcell	*poc;

	poc = (optcell *) malloc(sizeof(optcell));
	if (poc == NULL) {
		return(NULL);
	}

	poc->idx = 1;
	poc->id = PMKPC_OPT_UNKNOWN;
	poc->arg = NULL;

	return(poc);
}


/******************
 optcell_destroy()

 DESCR
	destroy optcell structure

 IN
	poc : optcell structure

 OUT
	-
************************************************************************/

void optcell_destroy(optcell *poc) {
	free(poc); /* no more to free */
}


/***********
 pcgetopt()

 DESCR
	process command line options

 IN
	ac :	argument number
	av :	argument array
	poc :	optcell structure

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

bool pcgetopt(unsigned int ac, char *av[], optcell *poc) {
	static char		 buf[PMKPC_MAX_OPT_SIZE];
	char			*opt,
					*pstr;
	size_t			 l;
	unsigned int	 i,
					 idx;

	idx = poc->idx;

	if (idx >= ac) {
#ifdef PMKPC_DEBUG
		debugf("{pcgetopt} ac = %d", ac);
#endif
		/* no more args */
		return(false);
	}

	opt = av[idx];

	if ((opt[0] != '-') || (opt[1] != '-')) {
#ifdef PMKPC_DEBUG
		debugf("{pcgetopt} full opt = '%s'", opt);
#endif
		/* not an option */
		poc->arg = opt;
		return(false);
	} else {
		/* skip leading "--" */
		opt = opt + 2;
#ifdef PMKPC_DEBUG
		debugf("{pcgetopt} opt = '%s'", opt);
#endif

		/* option have argument ? */
		pstr = strchr(opt, PMKPC_ARG_SEP);
		if (pstr != NULL) {
			/* argument found */
			if (strlcpy_b(buf, opt, sizeof(buf)) == false) {
#ifdef PMKPC_DEBUG
				debugf("{pcgetopt} strlcpy failed for '%s'", opt);
#endif
				return(false);
			}

			/* delimit option name */
			buf[pstr - opt] = CHAR_EOS;

			/* save argument position */
			pstr++;
			poc->arg = pstr;
#ifdef PMKPC_DEBUG
		debugf("{pcgetopt} opt arg = '%s'", poc->arg);
#endif

			/* set opt back to the beginning of the option */
			opt = buf;

		}

		l = strlen(opt);
		idx++;
#ifdef PMKPC_DEBUG
debugf("{pcgetopt} idx = %d", idx);
#endif
	}

	for (i = 0 ; i < nbpcopt ; i++) {
		if (strncmp(pcoptions[i].name, opt, l) == 0) {
			/* known option */
			poc->id = pcoptions[i].id;
			poc->err = pcoptions[i].name;

			poc->idx = idx;
			return(true);
		}
	}

	poc->id = PMKPC_OPT_UNKNOWN;
	poc->err = opt;

	return(true);
}


/***********
 list_all()

 DESCR
	list all packages

 IN
	ppd :	XXX

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

bool list_all(pkgdata *ppd) {
	bool			  rval = true;
	char			 *mod,
					 *pcfile,
					**descr,
					  fmt[32];
	hkeys			 *phk;
	pkgcell			 *ppc;
	size_t			  len,
					  maxs = 0;
	unsigned int	  i;

	phk = hash_keys(ppd->files);

	descr = (char **)malloc(sizeof(char *) * phk->nkey);
	if (descr == NULL)
		return(false);

	for(i = 0 ; (i < phk->nkey) && (rval == true) ; i++) {
		mod = phk->keys[i];
		len = strlen(mod);
		if (len > maxs)
			maxs = len;

		pcfile = hash_get(ppd->files, mod);
		ppc = parse_pc_file(pcfile);
		if (ppc == NULL) {
			/* failed parsing */
			rval = false;
		} else {
			descr[i] = strdup(ppc->descr);
			pkgcell_destroy(ppc);
		}
	}

	/* build format string to align descriptions */
	if (snprintf_b(fmt, sizeof(fmt), "%%-%us %%s\n",
				(unsigned int)maxs) == false) {
		/* cleaning */
		hash_free_hkeys(phk);
		free(descr);
		return(false);
	}

	for(i = 0 ; i < phk->nkey ; i++) {
		if (rval == true) {
			printf(fmt, phk->keys[i], descr[i]);
		}

		/* clean no longer used string */
		free(descr[i]);
	}

	/* cleaning */
	hash_free_hkeys(phk);
	free(descr);

	return(true);
}


/********
 clean()

 DESCR
	clean XXX

 IN
	p_cd :	XXX

 OUT
	-
************************************************************************/

void clean(pcdata *p_cd) {
	/* clean data */
	if (p_cd->pda != NULL) {
		da_destroy(p_cd->pda);
	}
	if (p_cd->pht != NULL) {
		hash_destroy(p_cd->pht);
	}
	if (p_cd->ppd != NULL) {
		pkgdata_destroy(p_cd->ppd);
	}
}


/********
 usage()

 DESCR
 	pmkpc(1) usage

 IN
	-

 OUT
	-
************************************************************************/

void usage(void) {
	char			option[MAXPATHLEN];
	size_t			alen,	/* alignement length */
					olen,	/* option length */
					cursor;
	unsigned int	i;

	alen = strlen(PMKPC_USAGE_ALIGN);

	fprintf(stderr, "%s", PMKPC_USAGE_STR);
	cursor = strlen(PMKPC_USAGE_STR);

	for (i = 0; i < nbpcopt; i++) {
		strlcpy(option, PMKPC_USAGE_OPEN_OPT,
					sizeof(option)); /* no check needed */
		strlcat(option, pcoptions[i].name,
					sizeof(option)); /* no check needed */

		if (pcoptions[i].usagearg != NULL) {
			strlcat(option, "=",
					sizeof(option)); /* no check needed */
			strlcat(option, pcoptions[i].usagearg,
					sizeof(option)); /* no check needed */
		}

		strlcat(option, PMKPC_USAGE_CLOSE_OPT,
					sizeof(option)); /* no check needed */

		olen = strlen(option);
		cursor += olen;

		if (cursor > 79) {
			fprintf(stderr, "\n%s", PMKPC_USAGE_ALIGN);
			cursor = olen + alen;
		}

		fprintf(stderr, "%s", option);
	}
	fprintf(stderr, "\n");
}


/*******
 main()

 DESCR
	main loop
************************************************************************/

int main(int argc, char *argv[]) {
	FILE			*fp;
	bool			 opt_version = false,
					 opt_atl_vers = false,
					 opt_modvers = false,
					 opt_cmp_modvers = false,
					 opt_exists = false,
					 opt_listall = false,
					 opt_cflags = false,
					 opt_libs = false;
	cfgtcell		*pcc = NULL;
	cfgtdata		*pcd = NULL;
	char			*mod,
					*bpath,
					*opt,
					*pc_path,
					*pstr,
					*mvers = NULL,
					*pvers = NULL,
					 cmp_type = CHAR_EOS,
					 pc_cmd[MAXPATHLEN],
					 pc_buf[MAXPATHLEN],
					 buf[TMP_BUF_LEN];
	int				 r;
	optcell			*poc;
	pcdata			 gdata;
	pkgcell			*ppc;
	unsigned int	 i,
					 cflags_opts = 0,
					 libs_opts = 0;

	poc = optcell_init();
	if (poc == NULL) {
		errorf("cannot init optcell.");
		exit(EXIT_FAILURE);
	}

	gdata.pda = da_init();
	if (gdata.pda == NULL) {
		optcell_destroy(poc);
		errorf("cannot init dynary.");
		exit(EXIT_FAILURE);
	}

	gdata.ppd = pkgdata_init();
	if (gdata.ppd == NULL) {
		optcell_destroy(poc);
		clean(&gdata);
		errorf("cannot init pkgdata.");
		exit(EXIT_FAILURE);
	}

	/* initialise global data hash table */
	gdata.pht = hash_init(MAX_DATA_KEY);
	if (gdata.pht == NULL) {
		clean(&gdata);
		errorf("cannot initialize hash table for data.");
		exit(EXIT_FAILURE);
	}

	while (poc->idx != (unsigned int) argc) {
		if (pcgetopt(argc, argv, poc) == true) {
#ifdef PMKPC_DEBUG
			debugf("{main} id = %d", poc->id);
#endif
			/* found an option */
			switch (poc->id) {
				case PMKPC_OPT_VERSION :
					opt_version = true;
					break;

				case PMKPC_OPT_ATLPKGVERS :
					opt_atl_vers = true;
					pvers = poc->arg;
					break;

				case PMKPC_OPT_MODVERS :
					opt_modvers = true;
					break;

				case PMKPC_OPT_ATLVERS :
					cmp_type = 'a';
					opt_cmp_modvers = true;
					mvers = poc->arg;
					break;

				case PMKPC_OPT_EXTVERS :
					cmp_type = 'e';
					opt_cmp_modvers = true;
					mvers = poc->arg;
					break;

				case PMKPC_OPT_MAXVERS :
					cmp_type = 'm';
					opt_cmp_modvers = true;
					mvers = poc->arg;
					break;

				case PMKPC_OPT_CFLAGS :
					opt_cflags = true;
					break;

				case PMKPC_OPT_CFLAGS_ONLY_PATH	:
					cflags_opts = cflags_opts | PKGCFG_CFLAGS_I;
					opt_cflags = true;
					break;

				case PMKPC_OPT_CFLAGS_ONLY_OTHER :
					cflags_opts = cflags_opts | PKGCFG_CFLAGS_o;
					opt_cflags = true;
					break;

				case PMKPC_OPT_LIBS :
					opt_libs = true;
					break;

				case PMKPC_OPT_LIBS_ONLY_PATH :
					libs_opts = libs_opts | PKGCFG_LIBS_L;
					opt_libs = true;
					break;

				case PMKPC_OPT_LIBS_ONLY_LIB :
					libs_opts = libs_opts | PKGCFG_LIBS_l;
					opt_libs = true;
					break;

				case PMKPC_OPT_LIBS_ONLY_OTHER :
					libs_opts = libs_opts | PKGCFG_LIBS_o;
					opt_libs = true;
					break;

				case PMKPC_OPT_EXISTS :
					opt_exists = true;
					break;

				case PMKPC_OPT_LISTALL :
					opt_listall = true;
					break;

				case PMKPC_OPT_HELP :
					fprintf(stderr, "For detailed help "
						"please see the pmkpc(1) "
						"man page.\n");
					exit(EXIT_FAILURE);

				case PMKPC_OPT_USAGE :
					usage();
					exit(EXIT_FAILURE);

				case PMKPC_OPT_UNINST :
				case PMKPC_OPT_DEBUG :
				case PMKPC_OPT_VAR :
				case PMKPC_OPT_VAR_DEF :
				case PMKPC_OPT_VAR_PRNT :
				case PMKPC_OPT_VAR_SILC :
				case PMKPC_OPT_VAR_STDO :
					errorf("option '--%s' is not yet "
						"implemented.", poc->err);
					optcell_destroy(poc);
					clean(&gdata);
					exit(EXIT_FAILURE);
					break;

				case PMKPC_OPT_UNKNOWN :
				default :
					errorf("unknown option '--%s'.",
						poc->err);
					optcell_destroy(poc);
					clean(&gdata);
					exit(EXIT_FAILURE);
					break;
			}
		} else {
			mod = argv[poc->idx];

			if (mod[0] == '-') {
				switch (mod[1]) {
					case '?' :
						usage();
						exit(EXIT_FAILURE);
						break;
					default :
						errorf("unknown option -%c",
							mod[1]);
						exit(EXIT_SUCCESS);
						break;
				}
			} else {
				/* add new module */
				if (da_push(gdata.pda, strdup(mod)) == false) {
					errorf("unable to store module name in dynarray.");
#ifdef PMKPC_DEBUG
					debugf("{main} mod = '%s'", mod);
#endif
					exit(EXIT_FAILURE);
				}
#ifdef PMKPC_DEBUG
debugf("{main} new mod = '%s'", mod);
#endif
				poc->idx++;
			}
		}
	}

	optcell_destroy(poc);

	if (opt_version == true) {
		printf("%s\n", PMKPC_COMPAT_VERSION);
		clean(&gdata);
		exit(EXIT_SUCCESS);
	}

	if (opt_atl_vers == true) {
		clean(&gdata);
		/* check if compat version is at least the specified one */
		if (compare_version(pvers, PMKPC_COMPAT_VERSION) < 0) {
			exit(EXIT_FAILURE);
		} else {
			exit(EXIT_SUCCESS);
		}
	}

	fp = fopen(PREMAKE_CONFIG_PATH, "r");
	if (fp != NULL) {
		if (parse_pmkconf(fp, gdata.pht, PRS_PMKCONF_SEP, process_opt) == false) {
			/* parsing failed */
			clean(&gdata);
			fclose(fp);
			errorf("failed to parse '%s'.", PREMAKE_CONFIG_PATH);
			exit(EXIT_FAILURE);
#ifdef PMKPC_DEBUG
		} else {
debugf("{main} parsed '%s'", PREMAKE_CONFIG_PATH);
#endif
		}
		fclose(fp);
	} else {
		clean(&gdata);
		errorf("cannot open '%s' : %s.",
			PREMAKE_CONFIG_PATH, strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* try to get pkg-config lib path from pmk.conf */
	pstr = hash_get(gdata.pht, PMKCONF_PC_PATH_LIB);
	if (pstr == NULL) {
		clean(&gdata);
		errorf("unable to find pkg-config libdir.");
		exit(EXIT_FAILURE);
	}
	pc_path = process_string(pstr, gdata.pht);

	/* collect data */
	pkg_collect(pc_path, gdata.ppd);

	if (opt_listall == true) {
		/* display all gathered modules */
		if (list_all(gdata.ppd) == true) {
			exit(EXIT_SUCCESS);
		} else {
			exit(EXIT_FAILURE);
		}
	}


#ifdef PMKPC_DEBUG
	debugf("{main} usize = '%d'", da_usize(gdata.pda));
#endif
	for (i = 0 ; i < da_usize(gdata.pda) ; i++) {
		mod = da_idx(gdata.pda, i);
#ifdef PMKPC_DEBUG
		debugf("{main} mod = '%s' (i = %d)", mod, i);
#endif
		if (pkg_mod_exists(gdata.ppd, mod) == true) {
#ifdef PMKPC_DEBUG
		debugf("{main} module '%s' found", mod);
#endif
			ppc = pkg_cell_add(gdata.ppd, mod); /* ppc is part of ppd, don't destroy */

			/* display mod version */
			if (opt_modvers == true) {
				/* print module version */
				printf("%s\n", ppc->version);
			}

			/* check version */
			if (opt_cmp_modvers == true) {
				/* compare module version */
				r = compare_version(mvers, ppc->version);
				switch (cmp_type) {
					case 'a':
						if (r < 0) {
							clean(&gdata);
							/* XXX be more verbose ? */
							/*errorf("module version (%s) is smaller than %s",*/
							/*        ppc->version, mvers);                   */
							exit(EXIT_FAILURE);
						}
						break; /* not reached */

					case 'e':
						if (r != 0) {
							clean(&gdata);
							/* XXX be more verbose ? */
							/*errorf("module version (%s) is not equal to %s",*/
							/*        ppc->version, mvers);                   */
							exit(EXIT_FAILURE);
						}
						break; /* not reached */

					case 'm':
						if (r > 0) {
							clean(&gdata);
							/* XXX be more verbose ? */
							/*errorf("module version (%s) is greater than %s",*/
							/*        ppc->version, mvers);                   */
							exit(EXIT_FAILURE);
						}
						break; /* not reached */

					default:
						clean(&gdata);
						errorf("unknown comparison type !");
						exit(EXIT_FAILURE);
						break; /* not reached */
				}
			}

			if ((opt_cflags == true) || (opt_libs == true)) {
				/* get cflags and/or libs */
				if (pkg_recurse(gdata.ppd, mod) == false) {
					clean(&gdata);
					errorf("failed on recurse !");
					exit(EXIT_FAILURE);
				}

				if (opt_cflags == true) {
					/* display cflags */
					if (cflags_opts == 0) {
						cflags_opts = PKGCFG_CFLAGS_ALL;
					}

					printf("%s", pkg_get_cflags_adv(gdata.ppd, cflags_opts));
				}
				if (opt_libs == true) {
					/* if cflags have been displayed, add a space */
					if (opt_cflags == true) {
						printf(" ");
					}

					/* display libs */
					if (libs_opts == 0) {
						libs_opts = PKGCFG_LIBS_ALL;
					}

					printf("%s", pkg_get_libs_adv(gdata.ppd, libs_opts));
				}
				printf("\n");
			}
		} else {
#ifdef PMKPC_DEBUG
			debugf("module not found");
#endif

			/* init config tool data if needed */
			if (pcd == NULL) {
				pcd = parse_cfgt_file();
				if (pcd == NULL) {
					clean(&gdata);
					errorf("unable to load config tool data.");
					exit(EXIT_FAILURE);
				}
			}

			/* set config tool filename */
			if (cfgtcell_get_binary(pcd, mod, pc_cmd, sizeof(pc_cmd)) == false) {
				if (snprintf_b(pc_cmd, sizeof(pc_cmd),
						"%s-config", mod) == false) {
					errorf("failed to build configure tool name.");
					exit(EXIT_FAILURE);
				}
			}

			bpath = hash_get(gdata.pht, PMKCONF_PATH_BIN);
			if (bpath == NULL) {
				errorf("unable to get binary path.");
				exit(EXIT_FAILURE);
			}

			pcc = cfgtcell_get_cell(pcd, pc_cmd);

			/* looking for it in the path */
			if (get_file_path(pc_cmd, bpath, pc_buf, sizeof(pc_buf)) == true) {
				/* use CHECK_CONFIG */
#ifdef PMKPC_DEBUG
				debugf("Found alternative '%s' tool.", pc_cmd);
#endif

				if (opt_modvers == true) {
					/* check if specific option exists */
					if ((pcc != NULL) && (pcc->version != NULL)) {
						opt = pcc->version;
					} else {
						opt = CFGTOOL_OPT_VERSION;
					}

					if (ct_get_version(pc_buf, opt, buf, sizeof(buf)) == false) {
						clean(&gdata);
						errorf("cannot get version from '%s'.", pc_cmd);
						exit(EXIT_FAILURE);
					} else {
						printf("%s\n", buf);
					}
				}

				/* cflags and libs stuff */
				if ((opt_cflags == true) || (opt_libs == true)) {
					if (opt_cflags == true) {
						/* check if there is a special option */
						if ((pcc != NULL) && (pcc->cflags != NULL)) {
							opt = pcc->cflags;
						} else {
							opt = CFGTOOL_OPT_CFLAGS;
						}

						/* get cflags from config tool */
						if (ct_get_data(pc_buf, opt, "", buf, sizeof(buf)) == false) {
							errorf("cannot get CFLAGS.");
							exit(EXIT_FAILURE);
						} else {
							printf("%s ", buf);
						}
					}
					if (opt_libs == true) {
						/* check if there is a special option */
						if ((pcc != NULL) && (pcc->libs != NULL)) {
							opt = pcc->libs;
						} else {
							opt = CFGTOOL_OPT_LIBS;
						}

						/* get libs from config tool */
						if (ct_get_data(pc_buf, opt, "", buf, sizeof(buf)) == false) {
							errorf("cannot get LIBS.");
							exit(EXIT_FAILURE);
						} else {
							printf("%s ", buf);
						}
					}
					printf("\n");
				}
			} else {
				errorf("'%s' not found.", pc_cmd);
				exit(EXIT_FAILURE);
			}
		}
	}
#ifdef PMKPC_DEBUG
debugf("{main} destroy data");
#endif
	clean(&gdata);
	if (pcd != NULL) {
		cfgtdata_destroy(pcd);
	}

#ifdef PMKPC_DEBUG
debugf("End.");
#endif

	return(0);
}


syntax highlighted by Code2HTML, v. 0.9.1