/* $Id: pmkscan.c 1970 2007-04-13 21:14:05Z coudercd $ */
/*
* Copyright (c) 2003-2006 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 it first as if it was <sys/types.h> - this will avoid errors */
#include "compat/pmk_sys_types.h"
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <glob.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include "compat/pmk_ctype.h"
#include "compat/pmk_libgen.h"
#include "compat/pmk_stdio.h"
#include "compat/pmk_string.h"
#include "compat/pmk_unistd.h"
#include "common.h"
#include "dynarray.h"
#include "hash_tools.h"
#include "parse.h"
#include "pathtools.h"
#include "pmkscan.h"
#include "premake.h"
#include "tags.h"
#include "time.h"
/*#define PMKSCAN_DEBUG 1*/
/* file types **********************************************************/
scn_ext_t file_ext[] = {
{"*.1", FILE_TYPE_MAN1},
{"*.2", FILE_TYPE_MAN2},
{"*.3", FILE_TYPE_MAN3},
{"*.4", FILE_TYPE_MAN4},
{"*.5", FILE_TYPE_MAN5},
{"*.6", FILE_TYPE_MAN6},
{"*.7", FILE_TYPE_MAN7},
{"*.8", FILE_TYPE_MAN8},
{"*.9", FILE_TYPE_MAN9},
{"*.asm", FILE_TYPE_ASM},
{"*.C", FILE_TYPE_C},
{"*.c", FILE_TYPE_C},
{"*.cc", FILE_TYPE_C},
{"*.cpp", FILE_TYPE_CXX},
{"*.cxx", FILE_TYPE_CXX},
{"*.c++", FILE_TYPE_CXX},
{"*.dat", FILE_TYPE_DATA},
{"*.gif", FILE_TYPE_IMG},
{"*.H", FILE_TYPE_C},
{"*.h", FILE_TYPE_C},
{"*.hh", FILE_TYPE_C},
{"*.hpp", FILE_TYPE_CXX},
{"*.html", FILE_TYPE_HTML},
{"*.htm", FILE_TYPE_HTML},
{"*.hxx", FILE_TYPE_CXX},
{"*.h++", FILE_TYPE_CXX},
{"*.in", FILE_TYPE_TEMPL},
{"*.jpg", FILE_TYPE_IMG},
{"*.jpeg", FILE_TYPE_IMG},
{"*.l", FILE_TYPE_LEX},
{"*.pmk", FILE_TYPE_TEMPL},
{"*.png", FILE_TYPE_IMG},
{"*.S", FILE_TYPE_ASM},
{"*.s", FILE_TYPE_ASM},
{"*.txt", FILE_TYPE_TEXT},
{"*.xpm", FILE_TYPE_IMG},
{"*.y", FILE_TYPE_YACC}
};
size_t nb_file_ext = sizeof(file_ext) / sizeof(scn_ext_t);
lib_type_t lib_types[] = {
/*{LANG_LABEL_ASM, LIB_TYPE_ASM},*/
{LANG_LABEL_C, LIB_TYPE_C},
{LANG_LABEL_CXX, LIB_TYPE_CXX}
};
size_t nb_lib_types = sizeof(lib_types) / sizeof(lib_type_t);
/* pmkscan data parser options *****************************************/
/* common required options */
kw_t req_name[] = {
{KW_OPT_NAM, PO_STRING}
};
/* ADD_HEADER options */
kw_t opt_addhdr[] = {
{KW_OPT_LIB, PO_STRING},
{KW_OPT_PRC, PO_LIST},
{KW_OPT_SUB, PO_LIST}
};
kwopt_t kw_addhdr = {
req_name,
sizeof(req_name) / sizeof(kw_t),
opt_addhdr,
sizeof(opt_addhdr) / sizeof(kw_t)
};
/* ADD_LIBRARY options */
kw_t opt_addlib[] = {
{KW_OPT_PRC, PO_LIST}
};
kwopt_t kw_addlib = {
req_name,
sizeof(req_name) / sizeof(kw_t),
opt_addlib,
sizeof(opt_addlib) / sizeof(kw_t)
};
/* ADD_TYPE options */
kw_t opt_addtyp[] = {
{KW_OPT_HDR, PO_STRING},
{KW_OPT_MBR, PO_LIST}
};
kwopt_t kw_addtyp = {
req_name,
sizeof(req_name) / sizeof(kw_t),
opt_addtyp,
sizeof(opt_addtyp) / sizeof(kw_t)
};
prskw kw_pmkscan[] = {
{KW_CMD_ADDHDR, PSC_TOK_ADDHDR, PRS_KW_CELL, PRS_TOK_NULL, &kw_addhdr},
{KW_CMD_ADDLIB, PSC_TOK_ADDLIB, PRS_KW_CELL, PRS_TOK_NULL, &kw_addlib},
{KW_CMD_ADDTYP, PSC_TOK_ADDTYP, PRS_KW_CELL, PRS_TOK_NULL, &kw_addtyp}
};
size_t nbkwps = sizeof(kw_pmkscan) / sizeof(prskw);
/* pmkscan script parser options ***************************************/
/* DEFINE_LIB required options */
kw_t req_deflib[] = {
{KW_OPT_NAM, PO_STRING},
{KW_OPT_LINKER, PO_STRING},
{KW_OPT_SRCS, PO_LIST}
};
/* DEFINE_LIB options */
kw_t opt_deflib[] = {
{KW_OPT_HDRS, PO_LIST},
{KW_OPT_VMAJ, PO_STRING},
{KW_OPT_VMIN, PO_STRING}
};
kwopt_t kw_deflib = {
req_deflib,
sizeof(req_deflib) / sizeof(kw_t),
opt_deflib,
sizeof(opt_deflib) / sizeof(kw_t)
};
/* common required options */
kw_t req_dir[] = {
{KW_OPT_DIR, PO_STRING}
};
/* GEN_PMKFILE options */
kw_t opt_genpmk[] = {
{KW_OPT_ADVTAG, PO_BOOL},
{KW_OPT_CFGALT, PO_STRING},
{KW_OPT_DSC, PO_LIST},
{KW_OPT_EXTTAG, PO_LIST},
{KW_OPT_LIB, PO_LIST},
{KW_OPT_PMKALT, PO_STRING},
{KW_OPT_REC, PO_BOOL},
{KW_OPT_UNI, PO_BOOL}
};
kwopt_t kw_genpmk = {
req_dir,
sizeof(req_dir) / sizeof(kw_t),
opt_genpmk,
sizeof(opt_genpmk) / sizeof(kw_t)
};
/* GEN_MAKEFILE options */
kw_t opt_genmkf[] = {
{KW_OPT_DSC, PO_LIST},
{KW_OPT_EXTMKF, PO_STRING},
{KW_OPT_EXTTAG, PO_LIST},
{KW_OPT_LIB, PO_LIST},
{KW_OPT_NAM, PO_STRING},
{KW_OPT_MKFALT, PO_STRING},
{KW_OPT_REC, PO_BOOL},
{KW_OPT_UNI, PO_BOOL}
};
kwopt_t kw_genmkf = {
req_dir,
sizeof(req_dir) / sizeof(kw_t),
opt_genmkf,
sizeof(opt_genmkf) / sizeof(kw_t)
};
/* GEN_ZONE options */
kw_t opt_genzone[] = {
{KW_OPT_ADVTAG, PO_BOOL},
{KW_OPT_CFGALT, PO_STRING},
{KW_OPT_DSC, PO_LIST},
{KW_OPT_EXTMKF, PO_STRING},
{KW_OPT_EXTTAG, PO_LIST},
{KW_OPT_LIB, PO_LIST},
{KW_OPT_MKF, PO_BOOL},
{KW_OPT_MKFALT, PO_STRING},
{KW_OPT_NAM, PO_STRING},
{KW_OPT_PMK, PO_BOOL},
{KW_OPT_PMKALT, PO_STRING},
{KW_OPT_REC, PO_BOOL},
{KW_OPT_UNI, PO_BOOL}
};
kwopt_t kw_genzone = {
req_dir,
sizeof(req_dir) / sizeof(kw_t),
opt_genzone,
sizeof(opt_genzone) / sizeof(kw_t)
};
prskw kw_scanfile[] = {
{KW_CMD_GENPF, PSC_TOK_PMKF, PRS_KW_CELL, PRS_TOK_NULL, &kw_genpmk},
{KW_CMD_GENMF, PSC_TOK_MAKF, PRS_KW_CELL, PRS_TOK_NULL, &kw_genmkf},
{KW_CMD_GENZN, PSC_TOK_ZONE, PRS_KW_CELL, PRS_TOK_NULL, &kw_genzone},
{KW_CMD_DEFLIB, PSC_TOK_DEFLIB, PRS_KW_CELL, PRS_TOK_NULL, &kw_deflib}
};
size_t nbkwsf = sizeof(kw_scanfile) / sizeof(prskw);
/* global variables ****************************************************/
/* log file descriptor */
FILE *fp_log = NULL;
extern char *optarg;
extern int optind;
/******************************
* init and destroy functions *
***********************************************************************/
/********************
* scan_node_init() *
***********************************************************************
DESCR
initialize scan node
IN
fname : node file name
OUT
scan node structure
***********************************************************************/
scn_node_t *scan_node_init(char *fname) {
char *pstr;
scn_node_t *pnode;
size_t len;
/* allocate memory */
pnode = (scn_node_t *) malloc(sizeof(scn_node_t));
if (pnode != NULL) {
/* set filename */
pnode->fname = strdup(fname);
if (pnode->fname == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* build prefix name */
len = strlen(fname);
pstr = &fname[len];
while (pstr > fname) {
if (*pstr == '.') {
len = (size_t) (pstr - fname);
break;
} else {
pstr--;
}
}
/* get the size including null char */
len++;
pnode->prefix = (char *) malloc(len);
if (pnode->prefix == NULL) {
return(NULL);
}
strlcpy(pnode->prefix, fname, len);
/* init dynamic array of dependencies */
pnode->system_inc = da_init();
if (pnode->system_inc == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->local_inc = da_init();
if (pnode->local_inc == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->func_calls = da_init();
if (pnode->func_calls == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->func_decls = da_init();
if (pnode->func_decls == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->type_idtfs = da_init();
if (pnode->type_idtfs == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->src_deps = da_init();
if (pnode->src_deps == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->sys_deps = da_init();
if (pnode->sys_deps == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init dynamic array of dependencies */
pnode->obj_links = da_init();
if (pnode->obj_links == NULL) {
/* failed */
scan_node_destroy(pnode);
return(NULL);
}
/* init object dependency list */
pnode->obj_deps = NULL;
/* init dependency state */
pnode->isdep = false; /* XXX useful ? see scan_file() */
/* init main() procedure flag */
pnode->mainproc = false;
/* init dependency score */
pnode->score = 0;
/* object pointer or null */
pnode->obj_name = NULL;
/* target label */
pnode->label = NULL;
/* directory name */
pnode->dname = NULL;
}
/* return initialized structure or NULL */
return(pnode);
}
/***********************
* scan_node_destroy() *
***********************************************************************
DESCR
destroy scan node structure
IN
pnode : scan node structure
OUT
NONE
***********************************************************************/
void scan_node_destroy(scn_node_t *pnode) {
#ifdef PMKSCAN_DEBUG
/*debugf("destroying node '%s'", pnode->fname);*/
#endif /* PMKSCAN_DEBUG */
if (pnode->fname != NULL) {
free(pnode->fname);
}
if (pnode->obj_name != NULL) {
free(pnode->obj_name);
}
if (pnode->prefix != NULL) {
free(pnode->prefix);
}
if (pnode->label != NULL) {
free(pnode->label);
}
if (pnode->dname != NULL) {
free(pnode->dname);
}
if (pnode->system_inc != NULL) {
da_destroy(pnode->system_inc);
}
if (pnode->local_inc != NULL) {
da_destroy(pnode->local_inc);
}
if (pnode->func_calls != NULL) {
da_destroy(pnode->func_calls);
}
if (pnode->func_decls != NULL) {
da_destroy(pnode->func_decls);
}
if (pnode->type_idtfs != NULL) {
da_destroy(pnode->type_idtfs);
}
if (pnode->src_deps != NULL) {
da_destroy(pnode->src_deps);
}
if (pnode->sys_deps != NULL) {
da_destroy(pnode->sys_deps);
}
if (pnode->obj_links != NULL) {
da_destroy(pnode->obj_links);
}
free(pnode);
}
/*******************
* lib_cell_init() *
***********************************************************************
DESCR
initialise a library cell structure
IN
name : library name
srcs : object list
OUT
structure pointer or NULL
***********************************************************************/
lib_cell_t *lib_cell_init(char *name, dynary *srcs, dynary *hdrs, ltype_t type) {
char buffer[TMP_BUF_LEN],
ubuf[TMP_BUF_LEN];
lib_cell_t *plc;
#ifdef PMKSCAN_DEBUG
debugf("lib_cell_init(): processing '%s'", name);
#endif
plc = (lib_cell_t *) malloc(sizeof(lib_cell_t));
if (plc != NULL) {
/* set library filename */
snprintf(buffer, sizeof(buffer), "lib%s", name);
plc->lib_name = strdup(buffer);
/* set library name variable */
str_to_upper(ubuf, sizeof(ubuf), buffer);
plc->lib_label = strdup(ubuf);
/* init version numbers */
plc->lib_vmaj = NULL;
plc->lib_vmin = NULL;
/* set library sources variable */
snprintf(buffer, sizeof(buffer), MKF_OBJ_SRCS_VAR, ubuf);
plc->lib_srcs = strdup(buffer);
/* set library headers variable */
snprintf(buffer, sizeof(buffer), MKF_TRGT_HDRS_VAR, ubuf);
plc->lib_hdrs = strdup(buffer);
/* set library objects variable */
snprintf(buffer, sizeof(buffer), MKF_TRGT_OBJS_VAR, ubuf);
plc->lib_objs = strdup(buffer);
/* set static library variable name */
snprintf(buffer, sizeof(buffer), "%s_STATIC", ubuf);
plc->lib_static = strdup(buffer);
/* set shared library variable name */
snprintf(buffer, sizeof(buffer), "%s_SHARED", ubuf);
plc->lib_shared = strdup(buffer);
/* library linking type */
plc->type = type;
/* source dependencies */
plc->src_list = srcs;
/* header dependencies */
plc->hdr_list = hdrs;
/* object dependencies */
plc->obj_deps = da_init();
}
return(plc);
}
/**********************
* lib_cell_destroy() *
***********************************************************************
DESCR
free the given library cell structure
IN
plc : library cell to destroy
OUT
NONE
***********************************************************************/
void lib_cell_destroy(lib_cell_t *plc) {
/* destroy sources list */
da_destroy(plc->src_list);
/* destroy objects list */
da_destroy(plc->obj_deps);
/* destroy headers list */
if (plc->hdr_list != NULL) {
da_destroy(plc->hdr_list);
}
free(plc->lib_name);
free(plc->lib_srcs);
free(plc->lib_hdrs);
free(plc->lib_objs);
free(plc->lib_static);
free(plc->lib_shared);
}
/********************
* scan_zone_init() *
***********************************************************************
DESCR
initialize scan zone structure
IN
nodes : global nodes table
OUT
scan zone structure
***********************************************************************/
scn_zone_t *scan_zone_init(htable *nodes) {
scn_zone_t *pzone;
size_t i;
pzone = (scn_zone_t *) malloc(sizeof(scn_zone_t));
if (pzone != NULL) {
/* set global nodes table */
pzone->nodes = nodes;
/* init boolean flags */
pzone->advtag = true;
pzone->gen_pmk = false;
pzone->gen_mkf = false;
pzone->gen_lib = false;
pzone->recursive = false;
pzone->unique = true;
/* init file names */
pzone->cfg_name = PMKSCAN_CFGFILE;
pzone->mkf_name = PMKSCAN_MKFILE;
pzone->pmk_name = PMKSCAN_PMKFILE;
pzone->ext_mkf = NULL;
/* discard list */
pzone->discard = NULL;
/* extra tags */
pzone->exttags = NULL;
/* init file type flags */
for (i = 0 ; i < sizeof(pzone->found) ; i++) {
pzone->found[i] = false;
}
/* init lib type flags */
for (i = 0 ; i < sizeof(pzone->lib_type) ; i++) {
pzone->lib_type[i] = false;
}
/* init source flag */
pzone->found_src = false;
/* init zone tables */
pzone->objects = hash_init(1024); /* XXX should be autogrow enabled */
pzone->targets = hash_init(512); /* XXX should be autogrow enabled */
pzone->libraries = hash_init_adv(16, NULL, (void (*)(void *)) lib_cell_destroy, NULL); /* library cells */
pzone->h_checks = hash_init_adv(128, NULL, (void (*)(void *)) destroy_chk_cell, NULL); /* XXX can do better :) */
pzone->l_checks = hash_init_adv(128, NULL, (void (*)(void *)) destroy_chk_cell, NULL); /* XXX can do better :) */
pzone->t_checks = hash_init_adv(128, NULL, (void (*)(void *)) destroy_chk_cell, NULL); /* XXX can do better :) */
/* init directory list to scan */
pzone->dirlist = da_init();
/* init man pages dynary */
pzone->manpgs = da_init();
/* init data files dynary */
pzone->datafiles = da_init();
/* init templates dynary */
pzone->templates = da_init();
/* init generated files dynary */
pzone->generated = da_init();
/* init tags dynary */
pzone->tags = da_init();
}
return(pzone);
}
/***********************
* scan_zone_destroy() *
***********************************************************************
DESCR
destroy scan zone structure
IN
pzone : scan zone structure
OUT
NONE
***********************************************************************/
void scan_zone_destroy(scn_zone_t *pzone) {
if (pzone->objects != NULL) {
hash_destroy(pzone->objects);
}
if (pzone->targets != NULL) {
hash_destroy(pzone->targets);
}
if (pzone->libraries != NULL) {
hash_destroy(pzone->libraries);
}
if (pzone->h_checks != NULL) {
hash_destroy(pzone->h_checks);
}
if (pzone->l_checks != NULL) {
hash_destroy(pzone->l_checks);
}
if (pzone->t_checks != NULL) {
hash_destroy(pzone->t_checks);
}
if (pzone->dirlist != NULL) {
da_destroy(pzone->dirlist);
}
if (pzone->manpgs != NULL) {
da_destroy(pzone->manpgs);
}
if (pzone->datafiles != NULL) {
da_destroy(pzone->datafiles);
}
if (pzone->templates != NULL) {
da_destroy(pzone->templates);
}
if (pzone->generated != NULL) {
da_destroy(pzone->generated);
}
if (pzone->tags != NULL) {
da_destroy(pzone->tags);
}
/* don't destroy discard and extra tags lists */
free(pzone);
}
/******************************
* pmkfile specific functions *
***********************************************************************/
/*******************
* init_chk_cell() *
***********************************************************************
DESCR
initialize check cell
IN
NONE
OUT
pointer to new cell or NULL
***********************************************************************/
check_t *init_chk_cell(char *name) {
check_t *pchk;
pchk = (check_t *) malloc(sizeof(check_t));
if (pchk == NULL) {
return(NULL);
}
/* set check name */
pchk->name = strdup(name);
if (pchk->name == NULL) {
free(pchk);
return(NULL);
}
/* init procedure list */
pchk->procs = da_init();
if (pchk->procs == NULL) {
free(pchk->name);
free(pchk);
return(NULL);
}
/* init misc */
pchk->header = NULL;
pchk->library = NULL;
pchk->member = NULL;
pchk->subhdrs = NULL;
return(pchk);
}
/**********************
* destroy_chk_cell() *
***********************************************************************
DESCR
destroy allocated check cell
IN
pchk : check cell structure
OUT
NONE
***********************************************************************/
void destroy_chk_cell(check_t *pchk) {
free(pchk->name);
da_destroy(pchk->procs);
free(pchk);
}
/*****************
* mk_chk_cell() *
***********************************************************************
DESCR
make check cell
IN
pht : parser hash table
token : cell type token
OUT
pointer to new cell or NULL
***********************************************************************/
check_t *mk_chk_cell(htable *pht, int token) {
check_t *pchk;
pchk = (check_t *) malloc(sizeof(check_t));
if (pchk != NULL) {
/* get the name */
pchk->name = po_get_str(hash_get(pht, KW_OPT_NAM));
if (pchk->name == NULL) {
free(pchk);
return(NULL);
}
/* init */
pchk->procs = NULL;
pchk->header = NULL;
pchk->library = NULL;
pchk->member = NULL;
pchk->subhdrs = NULL;
/* specific stuff */
switch (token) {
case PSC_TOK_ADDHDR :
/* get procedure list */
pchk->procs = po_get_list(hash_get(pht, KW_OPT_PRC));
/* get eventual related library */
pchk->library = po_get_str(hash_get(pht, KW_OPT_LIB));
/* get eventual sub headers */
pchk->subhdrs = po_get_list(hash_get(pht, KW_OPT_SUB));
break;
case PSC_TOK_ADDLIB :
/* get procedure list */
pchk->procs = po_get_list(hash_get(pht, KW_OPT_PRC));
break;
case PSC_TOK_ADDTYP :
/* get eventual header */
pchk->header = po_get_str(hash_get(pht, KW_OPT_HDR));
/* get eventual header */
pchk->member = po_get_str(hash_get(pht, KW_OPT_MBR));
break;
}
}
return(pchk);
}
/*********************
* parse_data_file() *
***********************************************************************
DESCR
parse data from PMKSCAN_DATA file
IN
pdata : parsing data structure
scandata : scanning data structure
OUT
boolean (true on success)
***********************************************************************/
bool parse_data_file(prsdata *pdata, scandata *sdata) {
FILE *fd;
bool rval;
check_t *pchk;
prscell *pcell;
fd = fopen(PMKSCAN_DATA, "r");
if (fd == NULL) {
errorf("cannot open '%s' : %s.",
PMKSCAN_DATA, strerror(errno));
return false;
}
/* init hash tables */
sdata->headers = hash_init_adv(256, NULL, free, NULL);
sdata->libraries = hash_init_adv(256, NULL, free, NULL);
sdata->types = hash_init_adv(256, NULL, free, NULL);
rval = parse_pmkfile(fd, pdata, kw_pmkscan, nbkwps);
fclose(fd);
if (rval == false) {
errorf("parsing of data file failed.");
return(rval);
}
pcell = pdata->tree->first;
while (pcell != NULL) {
switch(pcell->token) {
case PSC_TOK_ADDHDR :
pchk = mk_chk_cell(pcell->data, pcell->token);
if (pchk == NULL) {
errorf("failed to initialize header check cell");
return false;
}
if (hash_add(sdata->headers, pchk->name, pchk) == HASH_ADD_FAIL) {
errorf("failed to add '%s'", pchk->name);
return false;
}
break;
case PSC_TOK_ADDLIB :
pchk = mk_chk_cell(pcell->data, pcell->token);
if (pchk == NULL) {
errorf("failed to initialize library check cell");
return false;
}
if (hash_add(sdata->libraries, pchk->name, pchk) == HASH_ADD_FAIL) {
errorf("failed to add '%s'", pchk->name);
return false;
}
break;
case PSC_TOK_ADDTYP :
pchk = mk_chk_cell(pcell->data, pcell->token);
if (pchk == NULL) {
errorf("failed to initialize type check cell");
return false;
}
if (hash_add(sdata->types, pchk->name, pchk) == HASH_ADD_FAIL) {
errorf("failed to add '%s'", pchk->name);
return false;
}
break;
default :
errorf("parsing of data file failed.");
return false;
break;
}
pcell = pcell->next;
}
return(rval);
}
/*******************
* conv_to_label() *
***********************************************************************
DESCR
convert a string to a tag
IN
str : string to convert
OUT
pointer to the tag buffer
***********************************************************************/
char *conv_to_label(ftype_t ltype, char *fmt, ...) {
static char buffer[TMP_BUF_LEN];
char *pbuf;
size_t s;
va_list plst;
/* language prefix */
switch(ltype) {
case FILE_TYPE_C :
s = strlcpy(buffer, PMKSCAN_LABEL_C, sizeof(buffer));
break;
case FILE_TYPE_CXX :
s = strlcpy(buffer, PMKSCAN_LABEL_CXX, sizeof(buffer));
break;
default :
s = 0;
}
/* adjust pointer to end of language prefix */
pbuf = buffer + s;
s = sizeof(buffer) - s;
/* produce formatted string in the buffer */
va_start(plst, fmt);
vsnprintf(pbuf, s, fmt, plst);
va_end(plst);
/* process the given string */
while ((*pbuf != '\0') && (s > 1)) {
/* check if we have an alphanumeric character */
if (isalnum(*pbuf) == 0) {
/* no, replace by an underscore */
*pbuf = '_';
} else {
/* yes, convert to uppercase if needed */
*pbuf = (char) tolower((int) *pbuf);
}
/* next character */
s--;
pbuf++;
}
/* end of string */
*pbuf = '\0';
return(buffer);
}
/**********************
* recurse_sys_deps() *
***********************************************************************
DESCR
gather recursively the system include dependencies
IN
nodes : nodes hash table
deps : dynary structure where to store dependencies
nodename : node name to process recursively
OUT
boolean
***********************************************************************/
bool recurse_sys_deps(htable *nodes, dynary *deps, char *nodename) {
char dir[PATH_MAX],
*pstr;
scn_node_t *pnode;
size_t i;
/* get node structure */
pnode = hash_get(nodes, nodename); /* should not fail */
if (pnode == NULL) {
#ifdef PMKSCAN_DEBUG
debugf("recurse_sys_deps() : node '%s' missing.", nodename);
#endif /* PMKSCAN_DEBUG */
return true;
}
/* process all system headers linked to this node */
for (i = 0 ; i < da_usize(pnode->system_inc) ; i++) {
pstr = (char *) da_idx(pnode->system_inc, i);
/* check if the system header is already listed as a dependency */
if (da_find(deps, pstr) == false) {
/* no, add it into the list */
if (da_push(deps, strdup(pstr)) == false) {
return false;
}
}
}
/* get directory */
extract_dir(nodename, dir, sizeof(dir));
/* look for all the local dependencies of the current node */
for (i = 0 ; i < da_usize(pnode->local_inc) ; i++) {
/* and recurse */
if (recurse_sys_deps(nodes, deps, (char *) da_idx(pnode->local_inc, i)) == false) {
return false;
}
}
return true;
}
/*****************
* add_library() *
***********************************************************************
DESCR
generate a library check if a record exists for the given library
IN
checks : checks hash table
library : library to add
psd : scandata structure
pn: node structure
OUT
boolean
***********************************************************************/
bool add_library(scn_zone_t *psz, char *library, scandata *psd, scn_node_t *pn) {
char *label,
*pstr,
*tag,
tmp[TMP_BUF_LEN];
check_t *pchk,
*pcrec;
size_t i,
s;
/* try to retrieve a check record for the given header */
pcrec = hash_get(psd->libraries, library);
if (pcrec == NULL) {
/* no record, skipping */
return true;
}
label = conv_to_label(pn->type, "library_%s", library);
pchk = hash_get(psz->l_checks, label);
if (pchk == NULL) {
/* add new check */
pchk = init_chk_cell(library);
if (pchk == NULL) {
/* allocation failed */
errorf("failed to init check cell");
return false;
}
if (hash_update(psz->l_checks, label, pchk) == HASH_ADD_FAIL) {
return false;
}
/* set language */
pchk->ftype = pn->type;
/* add header tag */
snprintf(tmp, sizeof(tmp), "lib%s", library);
tag = gen_basic_tag_def(tmp);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
}
/* look for related procedures */
if (pcrec->procs != NULL) {
s = da_usize(pcrec->procs);
for (i = 0 ; i < s ; i++) {
pstr = da_idx(pcrec->procs, i);
/* if procedure has been found in parsing */
if (da_find(pn->func_calls, pstr) == true) {
/* if it has not been added in the check yet */
if (da_find(pchk->procs, pstr) == false) {
/* add in the list of function to check */
da_push(pchk->procs, strdup(pstr));
psc_log(NULL, "Node '%s': found procedure '%s'\n", pn->fname, pstr);
/* add header tag */
tag = gen_basic_tag_def(pstr);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
}
}
}
}
return true;
}
/******************
* check_header() *
***********************************************************************
DESCR
generate an header check if a record exists for the given header
IN
checks : checks hash table
header : header to process
psd : scandata structure
pn: node structure
OUT
boolean
TODO
add check if LIBRARY is specified
***********************************************************************/
bool check_header(scn_zone_t *psz, char *header, scandata *psd, scn_node_t *pn) {
char *label,
*pstr,
*tag;
check_t *pchk,
*pcrec;
size_t i,
s;
/* try to retrieve a check record for the given header */
pcrec = hash_get(psd->headers, header);
if (pcrec == NULL) {
/* no record, skipping */
return true;
}
label = conv_to_label(pn->type, "header_%s", header);
pchk = hash_get(psz->h_checks, label);
if (pchk == NULL) {
/* add new check */
pchk = init_chk_cell(header);
if (pchk == NULL) {
/* allocation failed */
errorf("failed to init check cell");
return false;
}
if (hash_update(psz->h_checks, label, pchk) == HASH_ADD_FAIL) {
return false;
}
/* set language */
pchk->ftype = pn->type;
/* link to eventual sub headers */
pchk->subhdrs = pcrec->subhdrs;
/* add AC style header tag */
tag = gen_basic_tag_def(header);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
/* add header tag */
tag = gen_tag_def(TAG_TYPE_HDR, header, NULL, NULL);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
}
/* look for related procedures */
if (pcrec->procs != NULL) {
s = da_usize(pcrec->procs);
for (i = 0 ; i < s ; i++) {
pstr = da_idx(pcrec->procs, i);
/* if procedure has been found in parsing */
if (da_find(pn->func_calls, pstr) == true) {
/* if it has not been added in the check yet */
if (da_find(pchk->procs, pstr) == false) {
/* add in the list of function to check */
da_push(pchk->procs, strdup(pstr));
psc_log(NULL, "Node '%s': found procedure '%s'\n", pn->fname, pstr);
/* add AC style header tag */
tag = gen_basic_tag_def(pstr);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
/* add header tag */
tag = gen_tag_def(TAG_TYPE_HDR_PRC, header, pstr, NULL);
if (da_find(psz->tags, tag) == false) {
da_push(psz->tags, strdup(tag));
}
}
}
}
}
if (pcrec->library != NULL) {
if (add_library(psz, pcrec->library, psd, pn) == false) {
return false;
}
}
return true;
}
/****************
* check_type() *
***********************************************************************
DESCR
generate a type check if a record exists for the given type
IN
checks : checks hash table
type : type to process
psd : scandata structure
pn: node structure
OUT
boolean
TODO
handle member ?
***********************************************************************/
bool check_type(scn_zone_t *psz, char *type, scandata *psd, scn_node_t *pn) {
char *label,
*pstr;
check_t *pchk,
*pcrec;
label = conv_to_label(pn->type, "type_%s", type);
if (hash_get(psz->t_checks, label) != NULL) {
/* check already exists */
return true;
}
/* try to retrieve a check record for the given header */
pcrec = hash_get(psd->types, type);
if (pcrec == NULL) {
/* no record */
return true;
}
/* add new check */
pchk = init_chk_cell(type);
if (pchk == NULL) {
/* allocation failed */
errorf("failed to init check cell");
return false;
}
/* set language */
pchk->ftype = pn->type;
if (pcrec->header != NULL) {
pchk->header = pcrec->header; /* XXX strdup ? */
}
if (hash_update(psz->t_checks, label, pchk) == HASH_ADD_FAIL) {
return false;
}
/* add AC style header tag */
pstr = gen_basic_tag_def(type);
if (da_find(psz->tags, pstr) == false) {
da_push(psz->tags, strdup(pstr));
}
/* add header tag */
pstr = gen_tag_def(TAG_TYPE_TYPE, type, NULL, NULL);
if (da_find(psz->tags, pstr) == false) {
da_push(psz->tags, strdup(pstr));
}
return true;
}
/****************
* gen_checks() *
***********************************************************************
DESCR
build pmkfile using gathered data
IN
psz : scanning zone data
pht : check component hash table
psd : parsing data structure
OUT
boolean
***********************************************************************/
bool gen_checks(scn_zone_t *psz, scandata *psd) {
char *pstr;
hkeys *phk;
scn_node_t *pn;
unsigned int i,
j;
/* for each node */
phk = hash_keys(psz->nodes);
if (phk == NULL) {
return true;
}
for(i = 0 ; i < phk->nkey ; i++) {
pn = hash_get(psz->nodes, phk->keys[i]); /* no check needed */
/* check types */
if (psd->types != NULL) {
/* process types */
for (j = 0 ; j < da_usize(pn->type_idtfs) ; j++) {
pstr = (char *) da_idx(pn->type_idtfs, j);
if (check_type(psz, pstr, psd, pn) == false) {
errorf("check_type() failed.");
hash_free_hkeys(phk);
return false;
}
}
}
/* check headers */
if (psd->headers != NULL) {
/* generate system dependencies */
recurse_sys_deps(psz->nodes, pn->sys_deps, pn->fname);
/* process system dependencies */
for (j = 0 ; j < da_usize(pn->sys_deps) ; j++) {
pstr = (char *) da_idx(pn->sys_deps, j);
if (check_header(psz, pstr, psd, pn) == false) {
errorf("check_header() failed.");
hash_free_hkeys(phk);
return false;
}
}
}
}
hash_free_hkeys(phk);
return true;
}
/*********************
* build_cmd_begin() *
***********************************************************************
DESCR
output body start of a command
IN
fp : file pointer
cmd : command name
label : command label
OUT
-
***********************************************************************/
void build_cmd_begin(FILE *fp, char *cmd, char *label) {
if (label == NULL) {
fprintf(fp, PMKF_CMD_NOLABEL, cmd);
} else {
fprintf(fp, PMKF_CMD_LABEL, cmd, label);
}
}
/*******************
* build_cmd_end() *
***********************************************************************
DESCR
output body end of a command
IN
fp : file pointer
OUT
-
***********************************************************************/
void build_cmd_end(FILE *fp) {
fprintf(fp, PMKF_CMD_END);
}
/*******************
* build_comment() *
***********************************************************************
DESCR
output a comment line at the main level (no indent)
IN
fp : file pointer
comment : comment text
OUT
-
***********************************************************************/
void build_comment(FILE *fp, char *fmt, ...) {
va_list plst;
/* build comment */
fprintf(fp, PMKF_COMMENT);
/* format string */
va_start(plst, fmt);
vfprintf(fp, fmt, plst);
va_end(plst);
fprintf(fp, "\n");
}
/******************
* build_quoted() *
***********************************************************************
DESCR
output a quoted string assignment
IN
fp : file pointer
vname : variable name
qstr : quoted string content
OUT
-
***********************************************************************/
void build_quoted(FILE *fp, char *vname, char *qstr) {
fprintf(fp, PMKF_VAR_QUOTED, vname, qstr);
}
/*******************
* build_boolean() *
***********************************************************************
DESCR
output a boolean assignment
IN
fp : file pointer
vname : variable name
bval : boolean value
OUT
-
***********************************************************************/
void build_boolean(FILE *fp, char *vname, bool bval) {
char *str;
if (bval == true) {
str = "TRUE";
} else {
str = "FALSE";
}
fprintf(fp, PMKF_VAR_BOOL, vname, str);
}
/****************
* build_list() *
***********************************************************************
DESCR
output a list assignment (if the list is not empty)
IN
fp : file pointer
vname : variable name
list : item list
OUT
-
***********************************************************************/
bool build_list(FILE *fp, char *vname, dynary *list) {
size_t i,
s;
if (list == NULL) {
return true;
}
/* get number of items */
s = da_usize(list);
/* if no items then leave */
if (s == 0) {
return false;
}
fprintf(fp, PMKF_VAR_LIST_BEG, vname);
/* process all items but the last */
s--;
for (i = 0 ; i < s ; i++) {
fprintf(fp, PMKF_VAR_LIST_ITEM, (char *) da_idx(list, i));
}
/* process last item */
fprintf(fp, PMKF_VAR_LIST_END, (char *) da_idx(list, s));
return true;
}
/**************
* set_lang() *
***********************************************************************
DESCR
IN
buf : storage buffer
siz : size of buffer
ltype : language type
OUT
boolean
***********************************************************************/
bool set_lang(FILE *fp, ftype_t ltype) {
char *lang;
/* set current language */
switch(ltype) {
case FILE_TYPE_C :
lang = PMKSCAN_LANG_C;
break;
case FILE_TYPE_CXX :
lang = PMKSCAN_LANG_CXX;
break;
default :
lang = NULL;
}
if (lang != NULL) {
/* output language name */
build_quoted(fp, "LANG", lang);
}
return true;
}
/******************
* ouput_header() *
***********************************************************************
DESCR
ouput an header check
IN
checks : checks hash table
header : header to process
psd : scandata structure
pn: node structure
OUT
boolean
***********************************************************************/
bool output_header(htable *checks, char *cname, FILE *fp) {
check_t *pchk;
pchk = hash_get(checks, cname);
if (pchk == NULL) {
return false;
}
/* output comment */
build_comment(fp, "check header %s", pchk->name);
/* output pmk command */
build_cmd_begin(fp, "CHECK_HEADER", cname);
/* output type name */
build_boolean(fp, "REQUIRED", false);
/* output header name */
build_quoted(fp, "NAME", pchk->name);
/* output language */
if (set_lang(fp, pchk->ftype) == false) {
return false;
}
/* output list (already handle empty list) */
build_list(fp, "FUNCTION", pchk->procs);
/* output list (already handle empty list) */
build_list(fp, "SUBHDR", pchk->subhdrs);
/* output end of command body */
build_cmd_end(fp);
fprintf(fp, "\n");
return true;
}
/*******************
* ouput_library() *
***********************************************************************
DESCR
ouput a library check
IN
checks : checks hash table
header : header to process
psd : scandata structure
pn: node structure
OUT
boolean
***********************************************************************/
bool output_library(htable *checks, char *cname, FILE *fp) {
check_t *pchk;
pchk = hash_get(checks, cname);
if (pchk == NULL) {
return false;
}
/* output comment */
build_comment(fp, "check library %s", pchk->name);
/* output pmk command */
build_cmd_begin(fp, "CHECK_LIB", cname);
/* output type name */
build_boolean(fp, "REQUIRED", false);
/* output header name */
build_quoted(fp, "NAME", pchk->name);
/* output language */
if (set_lang(fp, pchk->ftype) == false) {
return false;
}
/* output list (already handle empty list) */
build_list(fp, "FUNCTION", pchk->procs);
/* output end of command body */
build_cmd_end(fp);
fprintf(fp, "\n");
return true;
}
/*****************
* output_type() *
***********************************************************************
DESCR
ouput a type check
IN
checks : checks hash table
type : type to process
psd : scandata structure
pn: node structure
OUT
boolean
TODO
handle member ?
***********************************************************************/
bool output_type(htable *checks, char *cname, FILE *fp) {
check_t *pchk;
pchk = hash_get(checks, cname);
if (pchk == NULL) {
return false;
}
/* output comment */
build_comment(fp, "check type %s", pchk->name);
/* output pmk command */
build_cmd_begin(fp, "CHECK_TYPE", cname);
/* output type name */
build_boolean(fp, "REQUIRED", false);
/* output type name */
build_quoted(fp, "NAME", pchk->name);
/* output language */
if (set_lang(fp, pchk->ftype) == false) {
return false;
}
if (pchk->header != NULL) {
/* output header name */
build_quoted(fp, "HEADER", pchk->header);
}
/* output end of command body */
build_cmd_end(fp);
fprintf(fp, "\n");
return true;
}
/********************
* scan_build_pmk() *
***********************************************************************
DESCR
build pmkfile using gathered data
IN
fname : output file name
psz : scanning zone data
psd : parsing data structure
OUT
boolean
***********************************************************************/
bool scan_build_pmk(scn_zone_t *psz) {
FILE *fp;
char buf[MKF_OUTPUT_WIDTH * 2];
dynary *da;
hkeys *phk;
lib_cell_t *plc;
time_t now;
unsigned int i;
/* open output file */
fp = fopen(psz->pmk_name, "w");
if (fp == NULL) {
errorf("cannot open '%s' : %s.", psz->pmk_name, strerror(errno));
return false;
}
/* header comment ******************/
/* generating date */
now = time(NULL);
strftime(buf, sizeof(buf), STR_TIME_GEN, localtime(&now));
/* output formatted string */
build_comment(fp, PMKF_HDR_GEN, buf);
/* settings command ****************/
/* output command */
build_cmd_begin(fp, "SETTINGS", NULL);
/* template list comment */
build_comment(fp, PMKF_TRGT_CMT);
/* genere template list */
if (build_list(fp, "TARGET", psz->templates) == false) {
/* list is empty, produce comment */
build_comment(fp, "TARGET = ()\t# TO EDIT");
}
if (psz->gen_lib == true) {
/* compilers to detect */
da = da_init();
if (psz->found[FILE_TYPE_C] == true) {
/* check for C compiler */
da_push(da, strdup("C"));
}
if (psz->found[FILE_TYPE_CXX] == true) {
/* check for C++ compiler */
da_push(da, strdup("C++"));
}
build_list(fp, "DETECT", da);
da_destroy(da);
}
/* end of command */
build_cmd_end(fp);
fprintf(fp, "\n");
/* define command ******************/
/* warning comment */
build_comment(fp, PMKF_DEF_CMT);
/* output command */
build_cmd_begin(fp, "DEFINE", NULL);
/* output package name */
fprintf(fp, PMKF_DEF_PKG);
/* output directories */
fprintf(fp, PMKF_DEF_DIR);
if (psz->gen_lib == true) {
fprintf(fp, PMKF_DEF_LIB);
fprintf(fp, PMKF_DEF_INC); /* XXX add a check for headers existence ? */
}
/* output needed man directories */
if (psz->found[FILE_TYPE_MAN] == true) {
/* man pages directories */
for (i = 1 ; i < 10 ; i++) {
/* check if current category is needed */
if (psz->found[FILE_TYPE_MAN + i] == true) {
fprintf(fp, PMKF_DEF_MAN, i, i);
}
}
}
/* extra tags */
if (psz->exttags != NULL) {
da_sort(psz->exttags);
/* output each extra tag */
for (i = 0 ; i < da_usize(psz->exttags) ; i++) {
fprintf(fp, PMKF_DEF_TAG, (char *) da_idx(psz->exttags, i));
}
}
/* end of command */
build_cmd_end(fp);
fprintf(fp, "\n");
/* type checks *********************/
phk = hash_keys_sorted(psz->t_checks);
if (phk != NULL) {
/* output every type checks */
for(i = 0 ; i < phk->nkey ; i++) {
if (output_type(psz->t_checks, phk->keys[i], fp) == false) {
hash_free_hkeys(phk);
fclose(fp);
return false;
}
}
hash_free_hkeys(phk);
}
/* header checks *******************/
phk = hash_keys_sorted(psz->h_checks);
if (phk != NULL) {
/* output every header checks */
for(i = 0 ; i < phk->nkey ; i++) {
if (output_header(psz->h_checks, phk->keys[i], fp) == false) {
hash_free_hkeys(phk);
fclose(fp);
return false;
}
}
hash_free_hkeys(phk);
}
/* library checks ******************/
phk = hash_keys_sorted(psz->l_checks);
if (phk != NULL) {
/* output every library checks */
for(i = 0 ; i < phk->nkey ; i++) {
if (output_library(psz->l_checks, phk->keys[i], fp) == false) {
hash_free_hkeys(phk);
fclose(fp);
return false;
}
}
hash_free_hkeys(phk);
}
/* shared libraries ****************/
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
/* output every library */
for(i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
/* output command */
build_cmd_begin(fp, "BUILD_LIB_NAME", NULL);
/* output lib name */
build_quoted(fp, "NAME", phk->keys[i]);
/* output lib variables */
build_quoted(fp, "STATIC", plc->lib_static);
build_quoted(fp, "SHARED", plc->lib_shared);
if ((plc->lib_vmaj != NULL) && (plc->lib_vmin != NULL)) {
/* output major version */
build_quoted(fp, "MAJOR", plc->lib_vmaj);
/* output minor version */
build_quoted(fp, "MINOR", plc->lib_vmin);
/* output versioned variable name */
build_boolean(fp, "VERSION", true);
} else {
/* output non versioned variable name */
build_boolean(fp, "VERSION", false);
}
/* end of command */
build_cmd_end(fp);
}
hash_free_hkeys(phk);
}
fprintf(fp, "\n");
fclose(fp);
psc_log("Saved as '%s'\n", NULL, psz->pmk_name);
return true;
}
/********************
* scan_build_cfg() *
***********************************************************************
DESCR
build config file using gathered data
IN
fname : output file name
psz : scanning zone data
psd : parsing data structure
OUT
boolean
***********************************************************************/
bool scan_build_cfg(scn_zone_t *psz) {
FILE *fp;
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
time_t now;
unsigned int i;
fp = fopen(psz->cfg_name, "w");
if (fp == NULL) {
errorf("unable to open file '%s' for writing.", psz->cfg_name);
return false;
}
/* generating date */
now = time(NULL);
strftime(buf, sizeof(buf), STR_TIME_GEN, localtime(&now));
fprintf(fp, CFGF_HDR_GEN, buf);
if (psz->exttags != NULL) {
fprintf(fp, "/* extra tags */\n\n");
for (i = 0 ; i < da_usize(psz->exttags) ; i++) {
pstr = gen_basic_tag_def(da_idx(psz->exttags, i));
fprintf(fp, "@%s@\n\n", pstr);
}
}
fprintf(fp, "/* scanned tags */\n\n");
for (i = 0 ; i < da_usize(psz->tags) ; i++) {
fprintf(fp, "@%s@\n\n", (char *) da_idx(psz->tags, i));
}
fclose(fp);
psc_log("Saved as '%s'\n", NULL, psz->cfg_name);
return true;
}
/*******************************
* makefile specific functions *
***********************************************************************/
/***************
* find_deps() *
***********************************************************************
DESCR
check if function call list has at least one dependency with the
function declaration list
IN
da_fc : function call list
da_fd : function declaration list
OUT
boolean
***********************************************************************/
bool find_deps(dynary *da_fc, dynary *da_fd) {
char *str_fc,
*str_fd;
size_t siz;
unsigned int i,
j;
/* for each entry of the first dynary */
for (i = 0 ; i < da_usize(da_fc) ; i++) {
str_fc = da_idx(da_fc, i);
siz = strlen(str_fc) + 1;
/* compare with each entry of the second dynary */
for (j = 0 ; j < da_usize(da_fd) ; j++) {
str_fd = da_idx(da_fd, j);
if (strncmp(str_fc, str_fd, siz) == 0) {
psc_log(NULL, "\t\tFound common dependency '%s'\n", str_fc);
/* and return true if a common dependency is found */
return true;
}
}
}
/* no common stuff found */
return false;
}
/*****************
* extract_dir() *
***********************************************************************
DESCR
extract the directory portion of the given path
IN
path : original path
dirbuf : buffer to store the extracted directory
blen : buffer length
OUT
NONE
***********************************************************************/
void extract_dir(char *path, char *dirbuf, size_t blen) {
char buffer[PATH_MAX],
*p;
/*
work on a local copy due to implementations of dirname that do
not preserve original string
*/
strlcpy(buffer, path, sizeof(buffer)); /* XXX check */
/* get directory part */
p = dirname(buffer);
/* if the result start by "./" then skip it */
if ((p[0] == '.') && (p[1] == '/')) {
p = p + 2;
}
/* copy result in storage location */
strlcpy(dirbuf, p, blen); /* XXX check */
}
/****************
* build_path() *
***********************************************************************
DESCR
build a path from given directory and filename
IN
dir : directory string
file : file name string
buffer : buffer where to store the result
blen : buffer length
OUT
NONE
***********************************************************************/
void build_path(char *dir, char *file, char *buffer, size_t blen) {
char tmp[PATH_MAX],
chk[PATH_MAX];
if (*dir == '\0') {
/* directory empty, store only file name */
strlcpy(tmp, file, sizeof(tmp));
} else {
/* join directory and file names with the directory separator */
snprintf(tmp, sizeof(tmp), "%s/%s", dir, file);
}
/* check resulting path */
chkpath(tmp, chk);
strlcpy(buffer, chk, blen);
}
/**********************
* recurse_obj_deps() *
***********************************************************************
DESCR
gather recursively the local include dependencies
IN
nodes : nodes hash table
deps : dynary structure where to store dependencies
nodename : node name to process recursively
OUT
boolean
***********************************************************************/
bool recurse_obj_deps(htable *nodes, dynary *deps, char *nodename) {
char dir[PATH_MAX];
scn_node_t *pnode;
size_t i;
/* check if the node is already listed as target dependency */
if (da_find(deps, nodename) == true) {
/* yes, skip processing */
return true;
}
/* else add the new dependency */
if (da_push(deps, strdup(nodename)) == false) {
return false;
}
/* get node structure */
pnode = hash_get(nodes, nodename); /* should not fail */
if (pnode == NULL) {
#ifdef PMKSCAN_DEBUG
debugf("recurse_obj_deps() : node '%s' missing.", nodename);
#endif /* PMKSCAN_DEBUG */
return true;
}
/* get directory */
extract_dir(nodename, dir, sizeof(dir));
/* look for all the local dependencies of the current node */
for (i = 0 ; i < da_usize(pnode->local_inc) ; i++) {
/* and recurse */
if (recurse_obj_deps(nodes, deps, (char *)da_idx(pnode->local_inc, i)) == false) {
return false;
}
}
return true;
}
/*****************
* gen_objects() *
***********************************************************************
DESCR
generate objects from the nodes
IN
psz : scanning zone data
OUT
boolean
***********************************************************************/
bool gen_objects(scn_zone_t *psz) {
char buf[PATH_MAX],
*pstr;
hkeys *phk;
scn_node_t *pnode,
*pn;
unsigned int i,
j;
phk = hash_keys(psz->nodes);
if (phk == NULL) {
/* no objects to process */
psc_log("No objects to generate.\n", NULL);
return true;
}
for(i = 0 ; i < phk->nkey ; i++) {
pnode = hash_get(psz->nodes, phk->keys[i]); /* XXX check needed ??? (think no) */
#ifdef PMKSCAN_DEBUG
debugf("score of '%s' = %d", phk->keys[i], pnode->score);
#endif /* PMKSCAN_DEBUG */
psc_log(NULL, "\tScore of '%s' = %d\n", phk->keys[i], pnode->score);
/*
if we got a node with a score of 0 then it should
be an object
*/
if (pnode->score == 0) {
/* build object name */
strlcpy(buf, pnode->prefix, sizeof(buf));
strlcat(buf, OBJ_SUFFIX, sizeof(buf));
psc_log(NULL, "\tAdding node '%s' linked to '%s' into object list\n", buf, pnode->fname);
/* add object reference */
if (hash_update_dup(psz->objects, buf, pnode->fname) == HASH_ADD_FAIL) {
hash_free_hkeys(phk);
errorf("failed to update '%s' value with '%s'.", buf, pnode->fname);
return false;
}
psc_log(NULL, "\tProcessing '%s'\n", buf);
/* set object name */
pnode->obj_name = strdup(buf);
/* build and store label name */
str_to_upper(buf, sizeof(buf), pnode->prefix);
pnode->label = strdup(buf);
/* generate object's source dependencies */
recurse_obj_deps(psz->nodes, pnode->src_deps, pnode->fname);
/* for each local include */
for (j = 0 ; j < da_usize(pnode->local_inc) ; j++) {
pstr = da_idx(pnode->local_inc, j);
pn = hash_get(psz->nodes, pstr);
if (pn == NULL) {
#ifdef PMKSCAN_DEBUG
debugf("gen_objects() : node '%s' missing.", pstr);
#endif /* PMKSCAN_DEBUG */
continue;
}
/* check for common function declarators */
if (find_deps(pnode->func_decls, pn->func_decls) == true) {
#ifdef PMKSCAN_DEBUG
debugf("adding object link '%s' dependency to node '%s'", pnode->obj_name, pn->fname);
#endif /* PMKSCAN_DEBUG */
psc_log(NULL, "\t\tAdding object link '%s' dependency to node '%s'", pnode->obj_name, pn->fname);
/* and set object link if common declarator is found */
if (da_push(pn->obj_links, strdup(pnode->obj_name)) == false) {
hash_free_hkeys(phk);
errorf("failed to push '%s' into objects linking dependencies of '%s'.", buf, pn->fname);
return false;
}
}
}
/* extra stuff */
if (pnode->type == FILE_TYPE_ASM) {
/* try to find optionnal header file for assembly functions */
for(j = 0 ; j < phk->nkey ; j++) {
pn = hash_get(psz->nodes, phk->keys[j]);
/* check for common function declarators */
if (find_deps(pnode->func_decls, pn->func_decls) == true) {
#ifdef PMKSCAN_DEBUG
debugf("adding object link '%s' dependency to node '%s'", pnode->obj_name, pn->fname);
#endif /* PMKSCAN_DEBUG */
/* and set object link if common declarator is found */
if (da_push(pn->obj_links, strdup(pnode->obj_name)) == false) {
hash_free_hkeys(phk);
errorf("failed to push '%s' into objects linking dependencies of '%s'.", buf, pn->fname);
return false;
}
}
}
}
}
}
hash_free_hkeys(phk);
return true;
}
/**********************
* recurse_src_deps() *
***********************************************************************
DESCR
generate targets from the objects
IN
psz : scanning zone data
deps : dynary structure where to store object dependencies
name : node name to process
OUT
boolean
***********************************************************************/
bool recurse_src_deps(scn_zone_t *psz, dynary *deps, char *name) {
char *src,
*odep;
scn_node_t *pnode,
*pn;
size_t i,
j;
/* get node structure */
pnode = hash_get(psz->nodes, name);
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' START", pnode->fname);
#endif /* PMKSCAN_DEBUG */
/* for each source dependency */
for (i = 0 ; i < da_usize(pnode->src_deps) ; i++) {
/* get the node structure */
src = da_idx(pnode->src_deps, i);
pn = hash_get(psz->nodes, src);
if (pn == NULL) {
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : source '%s' missing.", src);
#endif /* PMKSCAN_DEBUG */
continue;
}
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' : src dep '%s' (%d)", pnode->fname, src, da_usize(pn->obj_links));
#endif /* PMKSCAN_DEBUG */
/* check each object link */
for (j = 0 ; j < da_usize(pn->obj_links) ; j++) {
/* get object name */
odep = da_idx(pn->obj_links, j);
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' : obj link '%s'", pnode->fname, odep);
#endif /* PMKSCAN_DEBUG */
/* check if already in the list */
if (da_find(deps, odep) == false) {
/* and add the object if not already present */
if (da_push(deps, strdup(odep)) == false) {
errorf("failed to add '%s'", odep);
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' : adding '%s' in deps", pnode->fname, odep);
#endif /* PMKSCAN_DEBUG */
/* recurse dependencies of this object */
src = hash_get(psz->objects, odep);
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' : => '%s'", pnode->fname, src);
#endif
if (recurse_src_deps(psz, deps, src) == false) {
/* recurse failed */
return false;
}
}
}
}
#ifdef PMKSCAN_DEBUG
debugf("recurse_src_deps() : node '%s' END", pnode->fname);
#endif /* PMKSCAN_DEBUG */
return true;
}
/*****************
* gen_targets() *
***********************************************************************
DESCR
generate targets from the objects
IN
psz : scanning zone data
OUT
boolean
***********************************************************************/
bool gen_targets(scn_zone_t *psz) {
char buf[PATH_MAX],
*nodename;
hkeys *phk;
scn_node_t *pnode;
unsigned int i;
phk = hash_keys(psz->objects);
if (phk == NULL) {
/* no objects, skip */
psc_log("No targets to generate.\n", NULL);
return true;
}
/* for each object */
for (i = 0 ; i < phk->nkey ; i++) {
/* get it's node structure */
nodename = hash_get(psz->objects, phk->keys[i]);
pnode = hash_get(psz->nodes, nodename); /* XXX check needed ??? (think no) */
/* if main procedure has been found then it's a target */
if (pnode->mainproc == true) {
/* adding in the target list */
if (hash_update_dup(psz->targets, pnode->prefix,
pnode->fname) == HASH_ADD_FAIL) {
return false;
}
/* init object deps */
pnode->obj_deps = da_init();
if (pnode->obj_deps == NULL) {
errorf("failed to init object dependencies dynary.");
return false;
}
/* build and store object name */
strlcpy(buf, pnode->prefix, sizeof(buf));
strlcat(buf, OBJ_SUFFIX, sizeof(buf));
if (da_find(pnode->obj_deps, buf) == false) {
if (da_push(pnode->obj_deps, strdup(buf)) == false) {
/* XXX err msg */
return false;
}
}
#ifdef PMKSCAN_DEBUG
debugf("START recurse_src_deps() for node '%s'", pnode->fname);
#endif /* PMKSCAN_DEBUG */
/* recurse source deps to find object deps */
if (recurse_src_deps(psz, pnode->obj_deps, pnode->fname) == false) {
/* failed */
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("END recurse_src_deps() for node '%s'\n", pnode->fname);
#endif /* PMKSCAN_DEBUG */
}
}
return true;
}
/*********************
* gen_lib_targets() *
***********************************************************************
DESCR
generate targets from the objects
IN
psz : scanning zone data
OUT
boolean
***********************************************************************/
bool gen_lib_targets(scn_zone_t *psz) {
char *srcname;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pnode;
unsigned int i,
j;
phk = hash_keys(psz->libraries);
if (phk == NULL) {
/* no libraries, skip */
psc_log("No library targets to generate.\n", NULL);
return true;
}
/* for each library */
for (i = 0 ; i < phk->nkey ; i++) {
/* get it's cell structure */
plc = hash_get(psz->libraries, phk->keys[i]);
/* check each object link */
for (j = 0 ; j < da_usize(plc->src_list) ; j++) {
/* get source name name */
srcname = da_idx(plc->src_list, j);
/* fetch source node */
pnode = hash_get(psz->nodes, srcname);
if (pnode == NULL) {
psc_log("cannot find node '%s'.\n", NULL, srcname);
return false;
}
if (da_find(plc->obj_deps, pnode->obj_name) == false) {
/* push object name of source file into dependencies */
if (da_push(plc->obj_deps, strdup(pnode->obj_name)) == false) {
/* XXX err msg */
return false;
}
}
#ifdef PMKSCAN_DEBUG
debugf("START recurse_src_deps() for source '%s'", srcname);
#endif /* PMKSCAN_DEBUG */
/* recurse source deps to find object deps */
if (recurse_src_deps(psz, plc->obj_deps, srcname) == false) {
/* failed */
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("END recurse_src_deps() for for source '%s'", srcname);
#endif /* PMKSCAN_DEBUG */
}
}
return true;
}
/*******************
* fprintf_width() *
***********************************************************************
DESCR
print in a file in a formated width
IN
width : width of a line
offset : actual column offset
fp : file stream
str : string to append
OUT
new offset
NOTE
NONE could support of a left limit for indentation
***********************************************************************/
size_t fprintf_width(size_t left, size_t width, size_t offset, FILE *fp, char *str) {
unsigned int i,
m;
size_t s,
t;
/* compute new offset with the string length */
s = strlen(str);
t = offset + s;
/* check if offset is greater than allowed width */
if (t < width) {
if (left != offset) {
/* not the first append */
fprintf(fp, " ");
t++;
}
/* got enough space on the line */
fprintf(fp, "%s", str);
offset = t;
} else {
/* compute number of tabs for the left margin */
m = (left / MKF_TAB_WIDTH);
if ((left % MKF_TAB_WIDTH) != 0) {
m++;
}
/* terminate current line */
fprintf(fp, " \\\n");
offset = 0;
/* build left margin */
for (i = 0 ; i < m ; i ++) {
fprintf(fp, "\t");
offset = offset + MKF_TAB_WIDTH;
}
/* print string */
fprintf(fp, "%s", str);
offset = offset + s;
}
return(offset);
}
/***********************
* mkf_output_header() *
***********************************************************************
DESCR
ouput makefile template header
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_header(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
int i;
size_t s;
time_t now;
/* generating date */
now = time(NULL);
strftime(buf, sizeof(buf), STR_TIME_GEN, localtime(&now));
/* set header */
fprintf(fp, MKF_HEADER_GEN, buf);
fprintf(fp, "\n# build tools\n");
/* assembly stuff */
if (psz->found[FILE_TYPE_ASM] == true) {
fprintf(fp, MKF_HEADER_ASM);
fprintf(fp, MKF_HEADER_CPP);
}
/* C stuff */
if (psz->found[FILE_TYPE_C] == true) {
fprintf(fp, MKF_HEADER_C);
}
/* C++ stuff */
if (psz->found[FILE_TYPE_CXX] == true) {
fprintf(fp, MKF_HEADER_CXX);
}
/* lex stuff */
if (psz->found[FILE_TYPE_LEX] == true) {
fprintf(fp, MKF_HEADER_LEX);
}
/* yacc stuff */
if (psz->found[FILE_TYPE_YACC] == true) {
fprintf(fp, MKF_HEADER_YACC);
}
/* library stuff */
if (psz->gen_lib == true) {
if (psz->lib_type[LIB_TYPE_C] == true) {
fprintf(fp, MKF_HDR_C_SL);
}
if (psz->lib_type[LIB_TYPE_CXX] == true) {
fprintf(fp, MKF_HDR_CXX_SL);
}
fprintf(fp, MKF_HEADER_AR);
fprintf(fp, MKF_HEADER_RANLIB);
}
/* misc stuff */
fprintf(fp, MKF_HEADER_MISC);
fprintf(fp, MKF_LINE_JUMP);
/* tool aliases */
fprintf(fp, "\n# tool aliases\n");
fprintf(fp, MKF_HEADER_ALIAS);
fprintf(fp, MKF_LINE_JUMP);
/* directories */
fprintf(fp, "# specific directories\n");
fprintf(fp, MKF_HEADER_DIR);
if (psz->found[FILE_TYPE_MAN] == true) {
/* main man pages directory */
fprintf(fp, MKF_MAN_DIR);
/* man pages directories */
for (i = 1 ; i < 10 ; i++) {
/* check if current category is needed */
if (psz->found[FILE_TYPE_MAN + i] == true) {
fprintf(fp, MKF_MANX_DIR, i, i);
}
}
}
/* library install directory */
if (psz->gen_lib == true) {
fprintf(fp, MKF_LIB_DIR);
fprintf(fp, MKF_INC_DIR); /* add a check */
}
/* system configuration directory */
fprintf(fp, MKF_SYSCONF_DIR);
fprintf(fp, MKF_LINE_JUMP);
/* package data */
fprintf(fp, "# packaging\n");
fprintf(fp, MKF_HEADER_DATA); /* XXX useful ? */
fprintf(fp, MKF_LINE_JUMP);
/* extra tags */
if (psz->exttags != NULL) {
fprintf(fp, "# extra tags\n");
da_sort(psz->exttags);
/* output each extra tag */
s = da_usize(psz->exttags);
for (i = 0 ; i < (int) s ; i++) {
pstr = (char *) da_idx(psz->exttags, i);
fprintf(fp, MKF_SUBSTVAR, pstr, pstr);
}
fprintf(fp, MKF_LINE_JUMP);
}
}
/***********************
* mkf_output_recurs() *
***********************************************************************
DESCR
ouput recursively gathered items
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_recurs(FILE *fp, scn_zone_t *psz) {
char *pstr;
size_t ofst,
lm,
i,
s;
/* XXX not used yet */
/*|+ generate the list of scanned directories +| */
/*s = da_usize(psz->dirlist); */
/*if (s > 0) { */
/* |+ get directory list +| */
/* fprintf(fp, "#\n# directory list\n#\n"); */
/* fprintf(fp, MKF_SDIR_LIST); */
/* */
/* da_sort(psz->dirlist); */
/* */
/* lm = strlen(MKF_SDIR_LIST); */
/* ofst = lm; */
/* for (i = 0 ; i < s ; i++) { */
/* |+ get directory +| */
/* pstr = da_idx(psz->dirlist, i); */
/* */
/* |+ add to the list +| */
/* ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, pstr);*/
/* } */
/* */
/* fprintf(fp, MKF_TWICE_JUMP); */
/*} */
/*|+ generate the list of template files +| */
/*s = da_usize(psz->templates); */
/*if (s > 0) { */
/* |+ get list of template files +| */
/* fprintf(fp, "#\n# list of generated files\n#\n"); */
/* fprintf(fp, MKF_TEMPLATES); */
/* */
/* da_sort(psz->templates); */
/* */
/* lm = strlen(MKF_TEMPLATES); */
/* ofst = lm; */
/* for (i = 0 ; i < s ; i++) { */
/* |+ get template file name +| */
/* pstr = da_idx(psz->templates, i); */
/* */
/* |+ add to the list +| */
/* ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, pstr);*/
/* } */
/* */
/* fprintf(fp, MKF_TWICE_JUMP); */
/*} */
/* generate the list of template generated files */
s = da_usize(psz->templates);
if (s > 0) {
/* get list of generated files */
fprintf(fp, "#\n# list of generated files\n#\n");
fprintf(fp, MKF_GEN_FILES);
da_sort(psz->templates);
for (i = 0 ; i < s ; i++) {
/* generate file name from template */
pstr = gen_from_tmpl(da_idx(psz->templates, i));
if (da_find(psz->generated, pstr) == false) {
/* add default config file template in the list */
if (da_push(psz->generated, strdup(pstr)) == false) {
/*return false; XXX make return boolean */
return;
}
}
}
lm = strlen(MKF_GEN_FILES);
ofst = lm;
s = da_usize(psz->generated);
for (i = 0 ; i < s ; i++) {
/* get generated file name */
pstr = da_idx(psz->generated, i);
/* add result to the list */
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, pstr);
}
fprintf(fp, MKF_TWICE_JUMP);
}
}
/*********************
* mkf_output_srcs() *
***********************************************************************
DESCR
output source lists
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_srcs(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
scn_node_t *pn;
size_t ofst,
lm,
i,
j;
/* check if objects exist */
phk = hash_keys_sorted(psz->objects);
if (phk == NULL) {
/* nothing to do */
return;
}
fprintf(fp, "#\n# source dependency lists\n#\n");
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->objects, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
/* object label */
snprintf(buf, sizeof(buf), MKF_OBJECT_SRCS, pn->label);
fprintf(fp, buf);
lm = strlen(buf);
ofst = lm;
da_sort(pn->src_deps);
/* append sources */
for (j = 0 ; j < da_usize(pn->src_deps) ; j++) {
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp,
(char *) da_idx(pn->src_deps, j));
}
fprintf(fp, MKF_TWICE_JUMP);
}
hash_free_hkeys(phk);
}
/*********************
* mkf_output_bins() *
***********************************************************************
DESCR
output library name macros
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_bins(FILE *fp, scn_zone_t *psz) {
char *pstr;
hkeys *phk;
scn_node_t *pn;
size_t i;
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
/* generate binary name variables */
fprintf(fp, "#\n# binary name macros\n#\n");
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
fprintf(fp, "%s=\t%s\n\n", pn->label, pn->prefix);
}
hash_free_hkeys(phk);
}
}
/*********************
* mkf_output_libs() *
***********************************************************************
DESCR
output library name macros
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_libs(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2];
hkeys *phk;
lib_cell_t *plc;
size_t ofst,
lm,
i,
j;
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
/* generate library name variables */
fprintf(fp, "#\n# library name macros\n#\n");
for (i = 0 ; i < phk->nkey ; i++) {
plc = hash_get(psz->libraries, phk->keys[i]);
fprintf(fp, "%s=\t%s\n", plc->lib_label, plc->lib_name);
fprintf(fp, MKF_SUBSTVAR, plc->lib_static, plc->lib_static);
fprintf(fp, MKF_SUBSTVAR, plc->lib_shared, plc->lib_shared);
fprintf(fp, MKF_LIB_HEADERS, plc->lib_label);
lm = strlen(buf);
ofst = lm;
da_sort(plc->hdr_list);
/* append sources */
for (j = 0 ; j < da_usize(plc->hdr_list) ; j++) {
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp,
(char *) da_idx(plc->hdr_list, j));
}
fprintf(fp, MKF_TWICE_JUMP);
}
hash_free_hkeys(phk);
}
}
/*********************
* mkf_output_objs() *
***********************************************************************
DESCR
output object lists
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_objs(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pn;
size_t ofst,
lm,
i,
j;
/* binaries *************************/
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
/* generate target deps */
fprintf(fp, "#\n# binary target dependency lists\n#\n");
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
/* target label */
snprintf(buf, sizeof(buf), MKF_TARGET_OBJS, pn->label);
fprintf(fp, buf);
lm = strlen(buf);
ofst = lm;
da_sort(pn->obj_deps);
/* append objects */
for (j = 0 ; j < da_usize(pn->obj_deps) ; j++) {
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp,
(char *) da_idx(pn->obj_deps, j));
}
fprintf(fp, MKF_TWICE_JUMP);
}
hash_free_hkeys(phk);
}
/* shared libraries ****************/
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
/* output every library */
fprintf(fp, "#\n# library target dependency lists\n#\n");
for(i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
/* target label */
snprintf(buf, sizeof(buf), MKF_VARHDR, plc->lib_objs);
fprintf(fp, buf);
lm = strlen(buf);
ofst = lm;
da_sort(plc->obj_deps);
/* append objects */
for (j = 0 ; j < da_usize(plc->obj_deps) ; j++) {
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst,
fp, (char *) da_idx(plc->obj_deps, j));
}
fprintf(fp, MKF_TWICE_JUMP);
}
hash_free_hkeys(phk);
}
}
/*************************
* mkf_output_suffixes() *
***********************************************************************
DESCR
ouput makefile template suffixes
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_suffixes(FILE *fp, scn_zone_t *psz) {
/* suffixes */
fprintf(fp, MKF_SUFFIXES);
/* assembly object build rule */
if (psz->found[FILE_TYPE_ASM] == true) {
fprintf(fp, MKF_BLD_ASM_OBJ);
}
/* C object build rule */
if (psz->found[FILE_TYPE_C] == true) {
fprintf(fp, MKF_BLD_C_OBJ);
}
/* C++ object build rule */
if (psz->found[FILE_TYPE_CXX] == true) {
fprintf(fp, MKF_BLD_CXX_OBJ);
}
/* lex source build rule */
if (psz->found[FILE_TYPE_LEX] == true) {
fprintf(fp, MKF_BLD_LEX_SRC);
}
/* yacc source build rule */
if (psz->found[FILE_TYPE_YACC] == true) {
fprintf(fp, MKF_BLD_YACC_SRC);
}
}
/***************************
* mkf_output_build_trgs() *
***********************************************************************
DESCR
output build targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_build_trgs(FILE *fp, scn_zone_t *psz) {
bool need_sep;
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pn;
size_t ofst,
lm,
i;
fprintf(fp, "#\n# target lists\n#\n");
/* generate main building target list */
fprintf(fp, "\n# building\n");
fprintf(fp, MKF_VARHDR, MKF_TRGT_BLD_VAR);
need_sep = false;
if (hash_nbkey(psz->targets) > 0) {
/* if binary targets have been found */
fprintf(fp, MKF_VAR, MKF_TRGT_ALL_BIN);
need_sep = true;
}
if (hash_nbkey(psz->libraries) > 0) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if library targets have been found */
fprintf(fp, MKF_VAR, MKF_LIB_BLD_VAR);
}
fprintf(fp, MKF_TWICE_JUMP);
if (hash_nbkey(psz->targets) > 0) {
/* generate main binary building target list */
fprintf(fp, MKF_VARHDR, MKF_TRGT_ALL_BIN);
/* list of binary targets */
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
lm = strlen(MKF_TRGT_ALL_BIN);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
snprintf(buf, sizeof(buf), "$(%s)", pn->label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
}
if (hash_nbkey(psz->libraries) > 0) {
/* generate main library building target list */
fprintf(fp, MKF_TRGT_ALL_LIB);
fprintf(fp, MKF_LINE_JUMP);
/* generate static libraries building target list */
fprintf(fp, MKF_VARHDR, MKF_STATIC_LIB_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_STATIC_LIB_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)", plc->lib_static);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
/* generate shared libraries building target list */
fprintf(fp, MKF_SUBSTVAR, MKF_SHARED_LIB_VAR, MKF_SHARED_LIB_VAR);
fprintf(fp, MKF_LINE_JUMP);
/* C shared lib support */
if (psz->lib_type[LIB_TYPE_C] == true) {
fprintf(fp, MKF_VARHDR, MKF_C_SHLIB_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_C_SHLIB_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_C) {
snprintf(buf, sizeof(buf), "$(%s)", plc->lib_shared);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
/* C++ shared lib support */
if (psz->lib_type[LIB_TYPE_CXX] == true) {
fprintf(fp, MKF_VARHDR, MKF_CXX_SHLIB_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_CXX_SHLIB_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_CXX) {
snprintf(buf, sizeof(buf), "$(%s)", plc->lib_shared);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
}
}
/***************************
* mkf_output_clean_trgs() *
***********************************************************************
DESCR
output build targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_clean_trgs(FILE *fp, scn_zone_t *psz) {
bool need_sep;
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pn;
size_t ofst,
lm,
i;
/* generate main cleaning target list */
fprintf(fp, "\n# cleaning\n");
fprintf(fp, MKF_VARHDR, MKF_TRGT_CLEAN_VAR);
need_sep = false;
if (hash_nbkey(psz->targets) > 0) {
/* if binary targets have been found */
fprintf(fp, MKF_VAR, MKF_BIN_CLEAN_VAR);
need_sep = true;
}
if (hash_nbkey(psz->libraries) > 0) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if library targets have been found */
fprintf(fp, MKF_VAR, MKF_LIB_CLEAN_VAR);
}
fprintf(fp, MKF_TWICE_JUMP);
if (hash_nbkey(psz->targets) != 0) {
/* generate main binary cleaning target list */
fprintf(fp, MKF_VARHDR, MKF_BIN_CLEAN_VAR);
/* list of binary targets */
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
lm = strlen(MKF_BIN_CLEAN_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
snprintf(buf, sizeof(buf), "$(%s)_clean", pn->label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_TWICE_JUMP);
}
if (hash_nbkey(psz->libraries) > 0) {
/* generate main library cleaning target list */
fprintf(fp, MKF_LIB_CLEAN_ALL);
fprintf(fp, MKF_LINE_JUMP);
/* generate static libraries building target list */
fprintf(fp, MKF_VARHDR, MKF_STLIB_CLN_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_STLIB_CLN_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)_static_clean", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_TWICE_JUMP);
/* generate shared libraries cleaning target list */
fprintf(fp, MKF_SUBSTVAR, MKF_SHLIB_CLN_VAR, MKF_SHLIB_CLN_VAR);
fprintf(fp, MKF_LINE_JUMP);
/* C shared lib support */
if (psz->lib_type[LIB_TYPE_C] == true) {
fprintf(fp, MKF_VARHDR, MKF_C_SHL_CLN_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_C_SHL_CLN_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_C) {
snprintf(buf, sizeof(buf), "$(%s)_shared_clean", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_LINE_JUMP);
}
/* C++ shared lib support */
if (psz->lib_type[LIB_TYPE_CXX] == true) {
fprintf(fp, MKF_VARHDR, MKF_CXX_SHL_CLN_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_CXX_SHL_CLN_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_CXX) {
snprintf(buf, sizeof(buf), "$(%s)_shared_clean", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_LINE_JUMP);
}
}
}
/**************************
* mkf_output_inst_trgs() *
***********************************************************************
DESCR
output build targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_inst_trgs(FILE *fp, scn_zone_t *psz) {
bool need_sep;
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pn;
size_t ofst,
lm,
i;
/* generate main installing target list */
fprintf(fp, "\n# installing\n");
/* main installing target list */
fprintf(fp, MKF_VARHDR, MKF_TRGT_INST_VAR);
need_sep = false;
if (hash_nbkey(psz->targets) > 0) {
/* if binary targets have been found */
fprintf(fp, MKF_TRGT_INST_BIN);
need_sep = true;
}
if (hash_nbkey(psz->libraries) > 0) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if library targets have been found */
fprintf(fp, MKF_TRGT_INST_LIB);
need_sep = true;
}
if (psz->found[FILE_TYPE_MAN] == true) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if manual pages have been found */
fprintf(fp, MKF_TRGT_INST_MAN);
need_sep = true;
}
if (psz->found[FILE_TYPE_DATA] == true) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if data files have been found */
fprintf(fp, MKF_TRGT_INST_DATA);
need_sep = true;
}
fprintf(fp, MKF_TWICE_JUMP);
if (hash_nbkey(psz->targets) > 0) {
/* generate main binary building target list */
fprintf(fp, MKF_VARHDR, MKF_BIN_INST_VAR);
/* list of binary targets */
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
lm = strlen(MKF_BIN_INST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
snprintf(buf, sizeof(buf), "$(%s)_install", pn->label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
}
if (hash_nbkey(psz->libraries) > 0) {
/* generate main library building target list */
fprintf(fp, MKF_LIB_INSTALL_ALL);
fprintf(fp, MKF_LINE_JUMP);
/* generate static libraries building target list */
fprintf(fp, MKF_VARHDR, MKF_STLIB_INST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_STLIB_INST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)_static_install", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
/* generate shared libraries building target list */
fprintf(fp, MKF_SUBSTVAR, MKF_SHLIB_INST_VAR, MKF_SHLIB_INST_VAR);
fprintf(fp, MKF_LINE_JUMP);
/* C shared lib support */
if (psz->lib_type[LIB_TYPE_C] == true) {
fprintf(fp, MKF_VARHDR, MKF_C_SHL_INST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_C_SHL_INST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_C) {
snprintf(buf, sizeof(buf), "$(%s)_shared_install", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
/* C++ shared lib support */
if (psz->lib_type[LIB_TYPE_CXX] == true) {
fprintf(fp, MKF_VARHDR, MKF_CXX_SHL_INST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_CXX_SHL_INST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_CXX) {
snprintf(buf, sizeof(buf), "$(%s)_shared_install", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
}
}
/****************************
* mkf_output_deinst_trgs() *
***********************************************************************
DESCR
output build targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_deinst_trgs(FILE *fp, scn_zone_t *psz) {
bool need_sep;
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
lib_cell_t *plc;
scn_node_t *pn;
size_t ofst,
lm,
i;
/* generate main deinstalling target list */
fprintf(fp, "\n# deinstalling\n");
/* main installing target list */
fprintf(fp, MKF_VARHDR, MKF_TRGT_DEINST_VAR);
need_sep = false;
if (hash_nbkey(psz->targets) > 0) {
/* if binary targets have been found */
fprintf(fp, MKF_VAR, MKF_BIN_DEINST_VAR);
need_sep = true;
}
if (hash_nbkey(psz->libraries) > 0) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if library targets have been found */
fprintf(fp, MKF_VAR, MKF_LIB_DEINST_VAR);
need_sep = true;
}
if (psz->found[FILE_TYPE_MAN] == true) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if manual pages have been found */
fprintf(fp, MKF_TRGT_DEINST_MAN);
need_sep = true;
}
if (psz->found[FILE_TYPE_DATA] == true) {
if (need_sep == true) {
/* put a separator if needed */
fprintf(fp, " ");
}
/* if data files have been found */
fprintf(fp, MKF_TRGT_DEINST_DATA);
need_sep = true;
}
fprintf(fp, MKF_TWICE_JUMP);
if (hash_nbkey(psz->targets) > 0) {
/* generate main binary building target list */
fprintf(fp, MKF_VARHDR, MKF_BIN_DEINST_VAR);
/* list of binary targets */
phk = hash_keys_sorted(psz->targets);
if (phk != NULL) {
lm = strlen(MKF_BIN_DEINST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
snprintf(buf, sizeof(buf), "$(%s)_deinstall", pn->label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
}
if (hash_nbkey(psz->libraries) > 0) {
/* generate main library building target list */
fprintf(fp, MKF_LIB_DEINSTALL_ALL);
fprintf(fp, MKF_LINE_JUMP);
/* generate static libraries building target list */
fprintf(fp, MKF_VARHDR, MKF_STLIB_DEINST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_STLIB_DEINST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)_static_deinstall", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
fprintf(fp, MKF_TWICE_JUMP);
/* generate shared libraries building target list */
fprintf(fp, MKF_SUBSTVAR, MKF_SHLIB_DEINST_VAR, MKF_SHLIB_DEINST_VAR);
fprintf(fp, MKF_LINE_JUMP);
/* C shared lib support */
if (psz->lib_type[LIB_TYPE_C] == true) {
fprintf(fp, MKF_VARHDR, MKF_C_SHL_DEINST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_C_SHL_DEINST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_C) {
snprintf(buf, sizeof(buf), "$(%s)_shared_deinstall", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
/* C++ shared lib support */
if (psz->lib_type[LIB_TYPE_CXX] == true) {
fprintf(fp, MKF_VARHDR, MKF_CXX_SHL_DEINST_VAR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_CXX_SHL_DEINST_VAR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
if (plc->type == LIB_TYPE_CXX) {
snprintf(buf, sizeof(buf), "$(%s)_shared_deinstall", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
}
}
/*************************
* mkf_output_man_trgs() *
***********************************************************************
DESCR
output man page targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_man_trgs(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
size_t ofst,
lm,
i,
j,
k;
if (psz->found[FILE_TYPE_MAN] == false) {
/* no man page, skip */
return;
}
/* generate man page lists */
for (i = 1 ; i < 10 ; i++) {
/* if category has at least one file */
if (psz->found[FILE_TYPE_MAN + i] == true) {
/* output category list macro */
snprintf(buf, sizeof(buf), MKF_FILE_MAN_VAR, (int) i);
fprintf(fp, buf);
lm = strlen(buf);
ofst = lm;
da_sort(psz->manpgs);
/* for each man page */
for (j = 0 ; j < da_usize(psz->manpgs) ; j++) {
/* get the last character */
pstr = da_idx(psz->manpgs, j);
k = strlen(pstr) - 1;
/*
if the numeric conversion of the character is equal
to the current man page category
*/
if ((size_t) atoi(&pstr[k]) == i) {
/* record it into the list */
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, pstr);
}
}
fprintf(fp, MKF_TWICE_JUMP);
}
}
}
/**************************
* mkf_output_data_trgs() *
***********************************************************************
DESCR
ouput data targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_data_trgs(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
size_t ofst,
lm,
i;
if (psz->found[FILE_TYPE_DATA] == false) {
/* no data files */
return;
}
/* data files */
fprintf(fp, MKF_FILE_DATA_VAR);
lm = strlen(buf);
ofst = lm;
da_sort(psz->datafiles);
/* for each data file */
for (i = 0 ; i < da_usize(psz->datafiles) ; i++) {
pstr = da_idx(psz->datafiles, i);
/* record it into the list */
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, pstr);
}
fprintf(fp, MKF_TWICE_JUMP);
}
/**************************
* mkf_output_obj_rules() *
***********************************************************************
DESCR
output object rules
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_obj_rules(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2],
*pstr;
hkeys *phk;
scn_node_t *pn;
size_t i;
phk = hash_keys_sorted(psz->objects);
if (phk == NULL) {
/* nothing to do */
return;
}
fprintf(fp, "#\n# object rules\n#\n");
for (i = 0 ; i < phk->nkey ; i++) {
pstr = hash_get(psz->objects, phk->keys[i]);
pn = hash_get(psz->nodes, pstr);
/* object label */
str_to_upper(buf, sizeof(buf), pn->prefix);
fprintf(fp, MKF_OBJECT_LABL, phk->keys[i], buf);
fprintf(fp, MKF_TWICE_JUMP);
}
hash_free_hkeys(phk);
}
/**************************
* mkf_output_trg_rules() *
***********************************************************************
DESCR
output target rules
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
************************************************************************/
void mkf_output_trg_rules(FILE *fp, scn_zone_t *psz) {
char *pstr,
*pname;
hkeys *phk;
scn_node_t *pn;
size_t i;
phk = hash_keys_sorted(psz->targets);
if (phk == NULL) {
/* nothing to do */
return;
}
if (phk != NULL) {
/* generate targets */
fprintf(fp, MKF_GTRGT_INST_BIN);
for (i = 0 ; i < phk->nkey ; i++) {
pstr = phk->keys[i];
pname = hash_get(psz->targets, phk->keys[i]);
pn = hash_get(psz->nodes, pname);
if (pn != NULL) {
fprintf(fp, "# %s binary targets\n", phk->keys[i]);
/* build target */
fprintf(fp, "$(%s): $(%s_OBJS)\n", pn->label, pn->label);
/* process node depending on its type */
switch (pn->type) {
/*case FILE_TYPE_ASM : XXX */
case FILE_TYPE_C :
fprintf(fp, MKF_TARGET_C, pn->label);
break;
case FILE_TYPE_CXX :
fprintf(fp, MKF_TARGET_CXX, pn->label);
break;
default :
fprintf(fp, MKF_TARGET_DEF, pn->label);
}
}
/* clean target */
fprintf(fp, MKF_TARGET_CLN, pn->label, pn->label, pn->label);
/* install target */
fprintf(fp, MKF_INST_BIN, pn->label, pn->label, pn->label, pn->label);
/* deinstall target */
fprintf(fp, MKF_DEINST_BIN, pn->label, pn->label);
}
hash_free_hkeys(phk);
}
}
/******************************
* mkf_output_lib_trg_rules() *
***********************************************************************
DESCR
output library target rules
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
************************************************************************/
void mkf_output_lib_trg_rules(FILE *fp, scn_zone_t *psz) {
char buf[MKF_OUTPUT_WIDTH * 2];
hkeys *phk;
lib_cell_t *plc;
size_t ofst,
lm,
i,
j;
phk = hash_keys_sorted(psz->libraries);
if (phk == NULL) {
/* nothing to do */
return;
}
/* generate targets */
fprintf(fp, MKF_GTRGT_INST_LIB);
fprintf(fp, "\n# library headers install target\n");
fprintf(fp, MKF_TRGT, MKF_TRGT_INST_LIBHDR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_TRGT_INST_LIBHDR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)_headers_install", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_TWICE_JUMP);
fprintf(fp, "\n# library headers deinstall target\n");
fprintf(fp, MKF_TRGT, MKF_TRGT_DEINST_LIBHDR);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if (phk != NULL) {
lm = strlen(MKF_TRGT_DEINST_LIBHDR);
ofst = lm;
for (i = 0 ; i < phk->nkey ; i++) {
/* get lib cell */
plc = hash_get(psz->libraries, phk->keys[i]);
snprintf(buf, sizeof(buf), "$(%s)_headers_deinstall", plc->lib_label);
ofst = fprintf_width(lm, MKF_OUTPUT_WIDTH, ofst, fp, buf);
}
hash_free_hkeys(phk);
}
fprintf(fp, MKF_TWICE_JUMP);
/* static library main targets */
fprintf(fp, MKF_TRGT_STLIBS);
/* list of library targets */
phk = hash_keys_sorted(psz->libraries);
if ((phk != NULL) && (psz->lib_type[LIB_TYPE_C] == true)) {
/* C shared libs targets */
fprintf(fp, MKF_TRGT_C_SHLIBS);
fprintf(fp, MKF_LINE_JUMP);
}
if ((phk != NULL) && (psz->lib_type[LIB_TYPE_CXX] == true)) {
/* C++ shared libs targets */
fprintf(fp, MKF_TRGT_CXX_SHLIBS);
fprintf(fp, MKF_LINE_JUMP);
}
for (i = 0 ; i < phk->nkey ; i++) {
plc = hash_get(psz->libraries, phk->keys[i]);
/* build target */
fprintf(fp, "# %s library targets\n", plc->lib_name);
fprintf(fp, "$(%s)_headers_install: $(%s_HEADERS)\n", plc->lib_label, plc->lib_label);
for (j = 0 ; j < da_usize(plc->hdr_list) ; j++) {
/* install of each header */
fprintf(fp, "\t$(INSTALL_DATA) %s $(DESTDIR)$(INCDIR)/%s\n", (char *) da_idx(plc->hdr_list, j), (char *) da_idx(plc->hdr_list, j));
}
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_headers_deinstall:\n", plc->lib_label);
for (j = 0 ; j < da_usize(plc->hdr_list) ; j++) {
/* install of each header */
fprintf(fp, "\t$(RM) $(RMFLAGS) $(DESTDIR)$(INCDIR)/%s\n", (char *) da_idx(plc->hdr_list, j));
}
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_clean:\n", plc->lib_label);
fprintf(fp, MKF_TARGET_LIB_CLN, plc->lib_objs);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, MKF_TARGET_SIMPLE, plc->lib_static, plc->lib_objs);
fprintf(fp, MKF_TARGET_LIB_STC, plc->lib_objs);
fprintf(fp, "$(%s)_static_clean: $(%s)_clean\n", plc->lib_label, plc->lib_label);
fprintf(fp, MKF_TARGET_LIB_CLN, plc->lib_static);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_static_install: $(%s)\n", plc->lib_label, plc->lib_static);
fprintf(fp, MKF_INST_STLIB, plc->lib_static, plc->lib_static);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_static_deinstall:\n", plc->lib_label);
fprintf(fp, "\t$(RM) $(RMFLAGS) $(DESTDIR)$(LIBDIR)/$(%s)\n", plc->lib_static);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, MKF_TARGET_SIMPLE, plc->lib_shared, plc->lib_objs);
switch(plc->type) {
case LIB_TYPE_C :
fprintf(fp, MKF_TARGET_SL_C, plc->lib_objs);
break;
case LIB_TYPE_CXX :
fprintf(fp, MKF_TARGET_SL_CXX, plc->lib_objs);
break;
default :
fprintf(fp, MKF_TARGET_LIB_SHD, plc->lib_objs);
}
fprintf(fp, "$(%s)_shared_clean: $(%s)_clean\n", plc->lib_label, plc->lib_label);
fprintf(fp, MKF_TARGET_LIB_CLN, plc->lib_shared);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_shared_install: $(%s)\n", plc->lib_label, plc->lib_shared);
fprintf(fp, MKF_INST_SHLIB, plc->lib_shared, plc->lib_shared);
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, "$(%s)_shared_deinstall:\n", plc->lib_label);
fprintf(fp, "\t$(RM) $(RMFLAGS) $(DESTDIR)$(LIBDIR)/$(%s)\n", plc->lib_shared);
fprintf(fp, MKF_LINE_JUMP);
}
hash_free_hkeys(phk);
fprintf(fp, MKF_TWICE_JUMP);
}
/*************************
* mkf_output_man_inst() *
***********************************************************************
DESCR
output manual pages install rule
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_man_inst(FILE *fp, scn_zone_t *psz) {
char *pstr;
size_t j,
k;
unsigned int i;
/* manual pages to install */
fprintf(fp, MKF_INST_MAN_H);
for (i = 1 ; i < 10 ; i++) {
/* if category has at least one file */
if (psz->found[FILE_TYPE_MAN + i] == true) {
/* output directory creation */
fprintf(fp, MKF_INST_MAN_D, i, i);
/* for each man page */
for (j = 0 ; j < da_usize(psz->manpgs) ; j++) {
/* get the last character */
pstr = da_idx(psz->manpgs, j);
k = strlen(pstr) - 1;
/*
if the numeric conversion of the character is equal
to the current man page category
*/
if ((size_t) atoi(&pstr[k]) == i) {
fprintf(fp, MKF_INST_MAN_P, pstr, i, basename(pstr));
}
}
}
}
fprintf(fp, MKF_LINE_JUMP);
/* manual pages to deinstall */
fprintf(fp, MKF_DEINST_MAN_H);
for (i = 1 ; i < 10 ; i++) {
/* if category has at least one file */
if (psz->found[FILE_TYPE_MAN + i] == true) {
/* output directory */
fprintf(fp, MKF_DEINST_MAN_D, i);
/* for each man page */
for (j = 0 ; j < da_usize(psz->manpgs) ; j++) {
/* get the last character */
pstr = da_idx(psz->manpgs, j);
k = strlen(pstr) - 1;
/*
if the numeric conversion of the character is equal
to the current man page category
*/
if ((size_t) atoi(&pstr[k]) == i) {
fprintf(fp, MKF_DEINST_MAN_P, i, basename(pstr));
}
}
}
}
fprintf(fp, MKF_LINE_JUMP);
}
/**************************
* mkf_output_data_trgs() *
***********************************************************************
DESCR
ouput data targets
IN
fp : file pointer
psz : scanning zone data
OUT
NONE
***********************************************************************/
void mkf_output_data_inst(FILE *fp, scn_zone_t *psz) {
char *pstr;
size_t i;
da_sort(psz->datafiles);
/* data files to install */
fprintf(fp, MKF_INST_DATA_H);
for (i = 0 ; i < da_usize(psz->datafiles) ; i++) {
pstr = da_idx(psz->datafiles, i);
fprintf(fp, MKF_INST_DATA_P, pstr, basename(pstr));
}
fprintf(fp, MKF_LINE_JUMP);
/* data files to deinstall */
fprintf(fp, MKF_DEINST_DATA_H);
for (i = 0 ; i < da_usize(psz->datafiles) ; i++) {
pstr = da_idx(psz->datafiles, i);
fprintf(fp, MKF_DEINST_DATA_P, basename(pstr));
}
fprintf(fp, MKF_LINE_JUMP);
}
/*********************
* scan_output_mkf() *
***********************************************************************
DESCR
build makefile using gathered data
IN
fname : file name
psz : scanning zone data
OUT
NONE
***********************************************************************/
bool scan_build_mkf(scn_zone_t *psz) {
FILE *fp,
*fp_ext;
bool ferr = false;
char buf[512];
size_t len;
fp = fopen(psz->mkf_name, "w");
if (fp == NULL) {
errorf("unable to open file '%s' for writing.", psz->mkf_name);
return false;
}
/* generate header and definitions */
mkf_output_header(fp, psz);
/* generate recursive data */
mkf_output_recurs(fp, psz);
/* generate object dependency lists */
mkf_output_srcs(fp, psz);
/* generate binary name macros */
mkf_output_bins(fp, psz);
/* generate library name macros */
mkf_output_libs(fp, psz);
/* generate target dependency lists */
mkf_output_objs(fp, psz);
/* generate building target list */
mkf_output_build_trgs(fp, psz);
/* generate cleaning target list */
mkf_output_clean_trgs(fp, psz);
/* generate installing target list */
mkf_output_inst_trgs(fp, psz);
/* generate deinstalling target list */
mkf_output_deinst_trgs(fp, psz);
/* manual pages to install/deinstall */
mkf_output_man_trgs(fp, psz);
/* data files */
mkf_output_data_trgs(fp, psz);
/* binaries to install/deinstall */
fprintf(fp, MKF_LINE_JUMP);
fprintf(fp, MKF_FILE_BIN_VAR);
fprintf(fp, MKF_FILE_SBIN_VAR);
/* generate suffixes */
if (psz->found_src == true) {
mkf_output_suffixes(fp, psz);
}
fprintf(fp, "\n#\n# generic targets\n#\n");
fprintf(fp, MKF_TARGET_ALL);
/* fprintf(fp, MKF_TARGET_CFG); XXX TO ENABLE: auto config update target */
fprintf(fp, MKF_TARGET_INST);
if (psz->found[FILE_TYPE_MAN] == true) {
mkf_output_man_inst(fp, psz);
}
if (psz->found[FILE_TYPE_DATA] == true) {
mkf_output_data_inst(fp, psz);
}
fprintf(fp, MKF_DIST_CLEAN);
if (psz->unique == true) {
fprintf(fp, MKF_LINE_JUMP);
} else {
/* recursive targets wrapper */
/* XXX not implemented yet */
}
/* generate objects */
mkf_output_obj_rules(fp, psz);
/* generate binary targets */
if (hash_nbkey(psz->targets) > 0) {
mkf_output_trg_rules(fp, psz);
}
/* generate library targets */
if (hash_nbkey(psz->libraries) > 0) {
mkf_output_lib_trg_rules(fp, psz);
}
/* extra to append */
if (psz->ext_mkf != NULL) {
fp_ext = fopen(psz->ext_mkf, "r");
if (fp_ext == NULL) {
errorf("unable to open file '%s' for reading.", psz->ext_mkf);
return false;
}
/* append extra content to the template */
while ((feof(fp_ext) == 0) && (ferr == false)) {
len = fread(buf, sizeof(char), sizeof(buf), fp_ext);
if (ferror(fp_ext) != 0) {
ferr = true;
} else {
fwrite(buf, sizeof(char), len, fp);
if (ferror(fp) != 0) {
ferr = true;
}
}
}
fclose(fp_ext);
}
fclose(fp);
/* append failed */
if (ferr == true) {
errorf("unable to append '%s' content into template.", psz->ext_mkf);
return false;
}
psc_log("Saved as '%s'\n", NULL, psz->mkf_name);
return true;
}
/********************
* common functions *
***********************************************************************/
/**************
* psc_log () *
***********************************************************************
DESCR
log on standard output and log file if enabled
IN
fmt : standard output format string
fmtl : log file format string
... : common parameters
OUT
NONE
***********************************************************************/
void psc_log(char *fmt, char *fmtl, ...) {
va_list vlst,
vlstl;
va_start(vlst, fmtl);
va_copy(vlstl, vlst);
if (fmt != NULL) {
vprintf(fmt, vlst);
}
/* if log is enabled */
if (fp_log != NULL) {
/* if a log format is not provided take the first */
if (fmtl == NULL) {
fmtl = fmt;
}
if (fmtl != NULL) {
vfprintf(fp_log, fmtl, vlstl);
}
}
va_end(vlst);
}
/******************
* str_to_upper() *
***********************************************************************
DESCR
store in the buffer the conversion in upper case of the string
IN
buf : storage buffer
siz : size of buffer
str : string to convert
OUT
NONE
***********************************************************************/
void str_to_upper(char *buf, size_t siz, char *str) {
while ((siz > 1) && (*str != '\0')) {
if ((*str == '.') || (*str == '/')) {
/*
replaces dot and slashes by underscores
ex: if we got "../" then replace by "___"
*/
*buf = '_';
} else {
/* else copy character in uppercase */
*buf = toupper(*str);
}
buf++;
str++;
siz--;
}
*buf = '\0';
}
/********************
* check_file_ext() *
***********************************************************************
DESCR
check the file extension and return the supposed file type
IN
fname : file name
OUT
file type
***********************************************************************/
ftype_t check_file_ext(char *fname) {
int i;
for (i = 0 ; i < (int) nb_file_ext ; i++) {
#ifdef PMKSCAN_DEBUG
/*debugf("check '%s' extension with file '%s'", file_ext[i].ext, fname);*/
#endif /* PMKSCAN_DEBUG */
/* check files that match known extension */
if (fnmatch(file_ext[i].ext, fname, 0) != FNM_NOMATCH) {
/* exit the loop */
return(file_ext[i].type);
}
}
/* unknown type */
return(FILE_TYPE_UNKNOWN);
}
/******************
* process_ppro() *
***********************************************************************
DESCR
called when a preprocessor directive is found
IN
data : parsing data
pstr : directive identifier
ppe : parsing engine structure
OUT
boolean
***********************************************************************/
bool process_ppro(void *data, char *pstr, prseng_t *ppe) {
char iname[PATH_MAX],
buf[PATH_MAX],
c;
scn_node_t *pnode;
scn_zone_t *psz;
psz = (scn_zone_t *) data;
pnode = psz->pnode;
if (strncmp(pstr, RKW_PP_INCL, strlen(pstr) + 1) == 0) {
prs_c_skip(ppe); /* XXX check ? */
c = prseng_get_char(ppe);
prseng_next_char(ppe); /* XXX check */
prseng_get_idtf(ppe, iname, sizeof(iname), PRS_C_IDTF_FNAME); /* XXX check ? */
switch(c) {
case '"' :
#ifdef PMKSCAN_DEBUG
debugf("process_ppro() : found local include '%s'", iname);
#endif /* PMKSCAN_DEBUG */
/* build relative path of the include */
build_path(pnode->dname, iname, buf, sizeof(buf));
#ifdef PMKSCAN_DEBUG
debugf("process_ppro() : adding include path '%s'", buf);
#endif /* PMKSCAN_DEBUG */
/* add include in depedencies */
if (da_push(pnode->local_inc, strdup(buf)) == false) {
errorf("unable to add '%s' in local deps", buf);
return false;
}
psc_log(NULL, "\t\tFound local include '%s'.\n", iname);
break;
case '<' :
#ifdef PMKSCAN_DEBUG
debugf("process_ppro() : found system include '%s'", iname);
#endif /* PMKSCAN_DEBUG */
/* add include in depedencies */
if (da_push(pnode->system_inc, strdup(iname)) == false) {
errorf("unable to add '%s' in sys deps", iname);
return false;
}
psc_log(NULL, "\t\tFound system include '%s'.\n", iname);
break;
default :
return false;
}
}
prs_c_line_skip(ppe); /* XXX check ? */
return true;
}
/***********************
* process_proc_call() *
***********************************************************************
DESCR
called when a procedure call is found
IN
data : parsing data
pstr : function call identifier
ppe : parsing engine structure
OUT
boolean
***********************************************************************/
bool process_proc_call(void *data, char *pstr, prseng_t *ppe) {
scn_node_t *pnode;
scn_zone_t *psz;
psz = (scn_zone_t *) data;
pnode = psz->pnode;
#ifdef PMKSCAN_DEBUG
debugf("process_proc_call() : found procedure call of '%s'", pstr);
#endif /* PMKSCAN_DEBUG */
/* add function in list */
if (da_push(pnode->func_calls, strdup(pstr)) == false) {
errorf("unable to add '%s' in function call list", pstr);
return false;
}
psc_log(NULL, "\t\tFound procedure call '%s'.\n", pstr);
return true;
}
/***********************
* process_proc_decl() *
***********************************************************************
DESCR
called when a procedure declaration is found
IN
data : parsing data
pstr : function declarator identifier
ppe : parsing engine structure
OUT
boolean
***********************************************************************/
bool process_proc_decl(void *data, char *pstr, prseng_t *ppe) {
scn_node_t *pnode;
scn_zone_t *psz;
psz = (scn_zone_t *) data;
pnode = psz->pnode;
#ifdef PMKSCAN_DEBUG
debugf("process_proc_decl() : found procedure declaration of '%s'", pstr);
#endif /* PMKSCAN_DEBUG */
/* add function in list */
if (da_push(pnode->func_decls, strdup(pstr)) == false) {
errorf("unable to add '%s' in function declaration list", pstr);
return false;
}
/* check for main procedure */
if (strncmp(pstr, PSC_MAIN_C, strlen(pstr)) == 0) {
#ifdef PMKSCAN_DEBUG
debugf("process_proc_decl() : found main procedure '%s' in '%s'", pstr, pnode->fname);
#endif /* PMKSCAN_DEBUG */
pnode->mainproc = true;
}
psc_log(NULL, "\t\tFound procedure declaration '%s'.\n", pstr);
return true;
}
/******************
* process_type() *
***********************************************************************
DESCR
called when a type identifier is found
IN
data : parsing data
pstr : type identifier
ppe : parsing engine structure
OUT
boolean
***********************************************************************/
bool process_type(void *data, char *pstr, prseng_t *ppe) {
scn_node_t *pnode;
scn_zone_t *psz;
psz = (scn_zone_t *) data;
pnode = psz->pnode;
/* add type in list */
if (da_push(pnode->type_idtfs, strdup(pstr)) == false) {
errorf("unable to add '%s' in type list", pstr);
return false;
}
psc_log(NULL, "\t\tFound type '%s'.\n", pstr);
return true;
}
/****************
* parse_file() *
***********************************************************************
DESCR
parse a file that has a known type
IN
pcmn : common parser structure
pnode : scan node structure
fname : file to parse
ft : file type
isdep : dependency flag
OUT
boolean
***********************************************************************/
bool parse_file(prs_cmn_t *pcmn, char *fname, ftype_t ft, bool isdep) {
FILE *fp;
char *ptr,
dir[PATH_MAX],
idir[PATH_MAX];
scn_node_t *pnode;
scn_zone_t *psz;
unsigned int i;
/* get misc data */
psz = (scn_zone_t *) pcmn->data;
/* check if this node is already existing */
pnode = hash_get(psz->nodes, fname);
if (pnode == NULL) {
#ifdef PMKSCAN_DEBUG
debugf("parse_file() : adding node for '%s'", fname); /* XXX */
#endif /* PMKSCAN_DEBUG */
/* open file */
fp = fopen(fname, "r");
if (fp == NULL) {
fprintf(stderr, "Warning : cannot open '%s' : %s.\n", fname, strerror(errno));
return true;
}
/* create new node */
pnode = scan_node_init(fname);
if (pnode == NULL) {
errorf("unable to initialize scan node");
fclose(fp);
return false;
}
/* set curret node */
psz->pnode = pnode;
/* get directory name */
extract_dir(fname, dir, sizeof(dir));
/* and store it for further use */
pnode->dname = strdup(dir);
pnode->type = ft;
switch (ft) {
case FILE_TYPE_ASM :
psz->found[FILE_TYPE_ASM] = true;
psz->found_src = true;
psc_log(NULL, "\tStart parsing of assembly file '%s'\n", fname);
if (prs_asm_file(pcmn, fp) == false) {
fclose(fp);
return false;
}
/* display parsed assembly file */
psc_log("a", "\tEnd of parsing of assembly file '%s'\n", fname);
break;
case FILE_TYPE_C :
case FILE_TYPE_CXX :
psz->found_src = true;
if (ft == FILE_TYPE_C) {
psz->found[FILE_TYPE_C] = true;
psc_log(NULL, "\tStart parsing of C file '%s'\n", fname);
} else {
psz->found[FILE_TYPE_CXX] = true;
psc_log(NULL, "\tStart parsing of C++ file '%s'\n", fname);
}
if (prs_c_file(pcmn, fp) == false) {
fclose(fp);
return false;
}
if (ft == FILE_TYPE_C) {
/* display parsed c file */
psc_log("c", "\tEnd of parsing of C file '%s'\n", fname);
} else {
/* display parsed c++ file */
psc_log("C", "\tEnd of parsing of C++ file '%s'\n", fname);
}
break;
}
/* close file */
fclose(fp);
}
/* update dependency state */
pnode->isdep = isdep;
if (isdep == true) {
/* update dependency score */
pnode->score++;
#ifdef PMKSCAN_DEBUG
debugf("parse_file() : score of '%s' = %d", pnode->fname, pnode->score);
#endif /* PMKSCAN_DEBUG */
}
/* add the node in the table of nodes */
if (hash_add(psz->nodes, fname, pnode) == HASH_ADD_FAIL) {
errorf("failed to add node '%s' in the hash table.", pnode->fname);
scan_node_destroy(pnode);
return false;
}
for (i = 0 ; i < da_usize(pnode->local_inc) ; i++) {
ptr = (char *) da_idx(pnode->local_inc, i);
#ifdef PMKSCAN_DEBUG
debugf("parse_file() : dir = '%s', inc = '%s'", pnode->dname, ptr);
#endif /* PMKSCAN_DEBUG */
/* scan local include */
if (scan_node_file(pcmn, ptr, true) == false) {
errorf("failed to scan file '%s'.", ptr);
return false;
}
/* add include directory in list */
extract_dir(ptr, idir, sizeof(idir));
#ifdef PMKSCAN_DEBUG
debugf("parse_file() : include extracted dir = '%s'", idir);
#endif /* PMKSCAN_DEBUG */
/* if the header directory is not yet in the scan list */
if ((*idir != '\0') && (da_find(psz->dirlist, idir) == false)) {
#ifdef PMKSCAN_DEBUG
debugf("parse_file() : adding '%s' in directory list to scan", idir);
#endif /* PMKSCAN_DEBUG */
/* add in zone directory list for further process */
da_push(psz->dirlist, strdup(idir));
/* and in the list of directorie to be scanned */
da_push(psz->dirscan, strdup(idir));
}
}
return true;
}
/********************
* scan_node_file() *
***********************************************************************
DESCR
scan a node file to extract useful data
IN
pcmn : common parser structure
fname : file to scan
isdep : flag to notice if fname is a dependency or not
OUT
boolean
***********************************************************************/
bool scan_node_file(prs_cmn_t *pcmn, char *fname, bool isdep) {
ftype_t ft;
scn_zone_t *psz;
#ifdef PMKSCAN_DEBUG
debugf("scan_node_file() : fname = '%s'", fname);
#endif /* PMKSCAN_DEBUG */
psz = (scn_zone_t *) pcmn->data;
ft = check_file_ext(fname);
switch (ft) {
case FILE_TYPE_ASM :
case FILE_TYPE_C :
case FILE_TYPE_CXX :
if (parse_file(pcmn, fname, ft, isdep) == false) {
/* XXX err msg ? */
return false;
}
break;
case FILE_TYPE_LEX :
/* XXX TODO */
psc_log(".", "\tFound Lex file '%s' (unsupported yet)\n", fname);
break;
case FILE_TYPE_YACC :
/* XXX TODO */
psc_log(".", "\tFound Yacc file '%s' (unsupported yet)\n", fname);
break;
case FILE_TYPE_MAN1 :
case FILE_TYPE_MAN2 :
case FILE_TYPE_MAN3 :
case FILE_TYPE_MAN4 :
case FILE_TYPE_MAN5 :
case FILE_TYPE_MAN6 :
case FILE_TYPE_MAN7 :
case FILE_TYPE_MAN8 :
case FILE_TYPE_MAN9 :
/* man pages will be processed later */
psz->found[FILE_TYPE_MAN] = true;
psz->found[ft] = true;
/* add man page in the list */
da_push(psz->manpgs, strdup(fname)); /* XXX check ? */
#ifdef PMKSCAN_DEBUG
debugf("scan_node_file() : added '%s' in psz->manpgs.", fname);
#endif /* PMKSCAN_DEBUG */
/* display man page file as recorded */
psc_log("m", "\tRecorded manual page '%s'\n", fname);
break;
case FILE_TYPE_DATA :
/* data files will be processed later */
psz->found[FILE_TYPE_DATA] = true;
/* add data file in the list */
da_push(psz->datafiles, strdup(fname)); /* XXX check ? */
#ifdef PMKSCAN_DEBUG
debugf("scan_node_file() : added '%s' in psz->datafiles.", fname);
#endif /* PMKSCAN_DEBUG */
/* display data file as recorded */
psc_log("d", "\tRecorded data file '%s'\n", fname);
break;
case FILE_TYPE_TEMPL :
/* data files will be processed later */
psz->found[FILE_TYPE_TEMPL] = true;
/* if not already added */
if (da_find(psz->templates, fname) == false) {
/* add template file in the list */
if (da_push(psz->templates, strdup(fname)) == false) {
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("scan_node_file() : added '%s' in psz->templates.", fname);
#endif /* PMKSCAN_DEBUG */
}
/* display data file as recorded */
psc_log("t", "\tRecorded template file '%s'\n", fname);
break;
default :
/* skip unsupported file extension */
/* display a file with unknown type */
psc_log(".", "\tFound file '%s' with unknown type\n", fname);
}
return true;
}
/**************
* scan_dir() *
***********************************************************************
DESCR
scan a directory to find and scan known file type
IN
pcmn : common parser structure
dir : directory to scan
recursive : recursive flag
OUT
boolean
***********************************************************************/
bool scan_dir(prs_cmn_t *pcmn, char *dir, bool recursive) {
struct dirent *pde;
struct stat tstat;
DIR *pd;
char buf[PATH_MAX],
*fname;
dynary *hdr_dir,
*to_scan = NULL;
scn_zone_t *psz;
size_t i;
psz = pcmn->data;
if ((psz->discard != NULL) && (da_find(psz->discard, dir) == true)) {
/* discard directory */
psc_log("Discarding directory '%s'\n", NULL, dir);
return true;
}
pd = opendir(dir);
if (pd == NULL) {
/* this is not a directory */
return false;
}
hdr_dir = da_init();
if (hdr_dir == NULL) {
/* XXX msg ? */
closedir(pd);
return false;
}
if (recursive == true) {
to_scan = da_init();
if (to_scan == NULL) {
/* XXX msg ? */
da_destroy(hdr_dir);
closedir(pd);
return false;
}
}
/* set pointer to dynary of directories to scan */
psz->dirscan = hdr_dir;
psc_log("Scanning directory '%s'\n", NULL, dir);
psc_log("[", "[\n");
/* check each directory's entries */
while ((pde = readdir(pd)) && (pde != NULL)) {
fname = pde->d_name;
#ifdef PMKSCAN_DEBUG
debugf("scan_dir() : checking entry '%s'", fname);
#endif /* PMKSCAN_DEBUG */
if (*fname == '.') {
/* skip every entries that starts with a dot */
#ifdef PMKSCAN_DEBUG
debugf("scan_dir() : skipping '%s'", fname);
#endif /* PMKSCAN_DEBUG */
continue;
}
/* build full path */
build_path(dir, fname, buf, sizeof(buf));
#ifdef PMKSCAN_DEBUG
debugf("scan_dir() : built path = '%s'", buf);
#endif /* PMKSCAN_DEBUG */
if (stat(buf, &tstat) == -1) {
continue;
}
/* if the entry is a directory */
if ((tstat.st_mode & S_IFDIR) != 0) {
/* and if recursivity is enabled */
if (recursive == true) {
/* then process the directory */
if (da_find(psz->dirlist, buf) == false) {
da_push(psz->dirlist, strdup(buf));
da_push(to_scan, strdup(buf));
}
}
/* go to next entry */
continue;
}
if (scan_node_file(pcmn, buf, false) == false) {
/* display scan failure for the file */
psc_log("!", "Failed to scan '%s'", fname);
}
}
closedir(pd);
psc_log("]\n", "]\n\n");
/* scan directories of relative headers (no recurse) */
for (i = 0 ; i < da_usize(hdr_dir) ; i++) {
scan_dir(pcmn, da_idx(hdr_dir, i), false);
}
da_destroy(hdr_dir);
if (recursive == true) {
/* recurse sub directories and directory found in headers */
for (i = 0 ; i < da_usize(to_scan) ; i++) {
scan_dir(pcmn, da_idx(to_scan, i), true);
}
da_destroy(to_scan);
}
return true;
}
/******************
* process_zone() *
***********************************************************************
DESCR
process a scanning zone
IN
pcmn : common parser structure
psd : scanning data structure
OUT
boolean (true on success)
***********************************************************************/
bool process_zone(prs_cmn_t *pcmn, scandata *psd) {
bool frslt,
rslt;
char sdir[PATH_MAX];
scn_zone_t *psz;
psz = pcmn->data;
/* save current working directory */
if (getcwd(sdir, sizeof(sdir)) == NULL) {
errorf("cannot get current working directory.");
return false;
}
/* change to zone directory */
if (chdir(psz->directory) != 0) {
errorf("cannot set working directory to '%s'.", psz->directory);
return false;
}
/* scanning directory */
psc_log("Starting file parsing in '%s':\n", NULL, psz->directory);
da_push(psz->dirlist, strdup("."));
frslt = scan_dir(pcmn, ".", psz->recursive);
if (frslt == false) {
psc_log("Parsing failed.\n\n", NULL);
} else {
psc_log("Parsing finished.\n\n", NULL);
/* pmkfile stuff */
if (psz->gen_pmk == true) {
/* compare with known functions in pmkscan db */
psc_log("Processing nodes for check generation ...\n", NULL);
rslt = gen_checks(psz, psd);
if (rslt == false) {
psc_log("Failed\n\n", NULL);
} else {
psc_log("Ok\n\n", NULL);
/* generate pmkfile */
psc_log("Generating %s ...\n", NULL, psz->pmk_name);
rslt = scan_build_pmk(psz);
if (rslt == true) {
psc_log("Ok\n\n", NULL);
} else {
psc_log("Failed\n\n", NULL);
}
/* generate config file */
psc_log("Generating %s ...\n", NULL, psz->cfg_name);
if (scan_build_cfg(psz) == true ) {
psc_log("Ok\n\n", NULL);
} else {
psc_log("Failed\n\n", NULL);
}
}
if (rslt == false) {
frslt = false;
}
}
/* makefile stuff */
if (psz->gen_mkf == true) {
/* scanning resulting nodes */
psc_log("Processing nodes for object generation ...\n", NULL);
rslt = gen_objects(psz);
if (rslt == false) {
psc_log("Failed\n\n", NULL);
} else {
psc_log("Ok\n\n", NULL);
/* scanning generated objects */
psc_log("Processing objects for binary target generation ...\n", NULL);
rslt = gen_targets(psz);
if (rslt == false) {
psc_log("Failed\n\n", NULL);
} else {
psc_log("Ok\n\n", NULL);
psc_log("Processing objects for library target generation ...\n", NULL);
rslt = gen_lib_targets(psz);
if (rslt == false) {
psc_log("Failed\n\n", NULL);
} else {
psc_log("Ok\n\n", NULL);
/* generate makefile */
psc_log("Generating %s ...\n", NULL, psz->mkf_name);
if (scan_build_mkf(psz) == true ) {
psc_log("Ok\n\n", NULL);
} else {
psc_log("Failed\n\n", NULL);
}
}
}
}
if (rslt == false) {
frslt = false;
}
}
}
/* come back to previously saved directory */
if (chdir(sdir) != 0) {
errorf("cannot set working directory back to '%s'.", sdir);
return false;
}
return(frslt);
}
/******************
* parse_deflib() *
***********************************************************************
DESCR
define library parameters
IN
XXX
OUT
boolean
***********************************************************************/
bool parse_deflib(htable *pht, htable *libs) {
char *name,
*linker = NULL;
dynary *srcs = NULL,
*hdrs = NULL;
int i;
lib_cell_t *plc;
ltype_t type = LIB_TYPE_UNKNOWN;
pmkobj *ppo;
/* get library name (REQUIRED) */
name = po_get_str(hash_get(pht, KW_OPT_NAM));
if (name == NULL) {
return false;
}
/* get source list (REQUIRED) */
ppo = hash_extract(pht, KW_OPT_SRCS); /* XXX duplicate ? */
if (ppo == NULL) {
return false;
}
srcs = po_get_list(ppo);
/* get header list */
ppo = hash_extract(pht, KW_OPT_HDRS); /* XXX duplicate ? */
if (ppo != NULL) {
hdrs = po_get_list(ppo);
}
/* get linker type */
linker = po_get_str(hash_get(pht, KW_OPT_LINKER));
/* check lib type */
for (i = 0 ; i < (int) nb_lib_types ; i++) {
if (strncmp(lib_types[i].lang, linker, strlen(lib_types[i].lang) + 1) == 0) {
type = lib_types[i].type;
break;
}
}
/* init lib cell */
plc = lib_cell_init(name, srcs, hdrs, type);
if (plc == NULL) {
return false;
}
/* get library major version number */
plc->lib_vmaj = po_get_str(hash_get(pht, KW_OPT_VMAJ));
/* get library minor version number */
plc->lib_vmin = po_get_str(hash_get(pht, KW_OPT_VMIN));
if (hash_add(libs, name, plc) == HASH_ADD_FAIL) {
lib_cell_destroy(plc);
return false;
}
psc_log("Recording library definition '%s'.\n", NULL, name);
return true;
}
/***********************
* parse_zone_opts() *
***********************************************************************
DESCR
XXX
IN
XXX
OUT
XXX
***********************************************************************/
bool parse_zone_opts(prs_cmn_t *pcmn, htable *pht, htable *libs) {
char *pdir,
*pstr;
dynary *da_l; /* library list */
pmkobj *ppo;
htable *tnodes;
lib_cell_t *plc;
scn_zone_t *psz;
size_t i;
/* init of nodes table */
tnodes = hash_init_adv(2048, NULL, (void (*)(void *))scan_node_destroy, NULL);
if (tnodes == NULL) {
/* XXX errmsg !! */
return false;
}
/* init zone structure */
psz = scan_zone_init(tnodes);
if (psz == NULL) {
/* XXX err msg */
hash_destroy(tnodes);
return false;
}
pcmn->data = psz;
/* get pmkfile switch */
ppo = hash_get(pht, KW_OPT_PMK);
if (ppo != NULL) {
psz->gen_pmk = po_get_bool(ppo);
if (psz->gen_pmk == true) {
/* alternate name for config file template */
ppo = hash_get(pht, KW_OPT_CFGALT);
if (ppo != NULL) {
pstr = po_get_str(ppo);
if (pstr == NULL) {
return false;
}
/* set config file template name */
psz->cfg_name = pstr;
} else {
/* add default config file template in the list */
if (da_push(psz->templates, strdup(PMKSCAN_CFGFILE)) == false) {
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("parse_zone_opts() : added '%s' in psz->templates.", PMKSCAN_CFGFILE);
#endif /* PMKSCAN_DEBUG */
}
/* alternate name for pmkfile template */
ppo = hash_get(pht, KW_OPT_PMKALT);
if (ppo != NULL) {
pstr = po_get_str(ppo);
if (pstr == NULL) {
return false;
}
/* set pmkfile file template name */
psz->pmk_name = pstr;
}
}
}
/* get makefile switch */
ppo = hash_get(pht, KW_OPT_MKF);
if (ppo != NULL) {
psz->gen_mkf = po_get_bool(ppo);
if (psz->gen_mkf == true) {
/* alternate name for makefile template */
ppo = hash_get(pht, KW_OPT_MKFALT); /* check new option */
if (ppo != NULL) {
pstr = po_get_str(ppo);
if (pstr == NULL) {
return false;
}
/* set makefile name */
psz->mkf_name = po_get_str(ppo);
/* add alternative makefile template in the list */
if (da_push(psz->templates, strdup(pstr)) == false) {
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("parse_zone_opts() : added '%s' in psz->templates.", pstr);
#endif /* PMKSCAN_DEBUG */
} else {
/* add default makefile template in the list */
if (da_push(psz->templates, strdup(PMKSCAN_MKFILE)) == false) {
return false;
}
#ifdef PMKSCAN_DEBUG
debugf("parse_zone_opts() : added '%s' in psz->templates.", PMKSCAN_MKFILE);
#endif /* PMKSCAN_DEBUG */
}
/* extra to append to makefile template */
ppo = hash_get(pht, KW_OPT_EXTMKF);
if (ppo != NULL) {
pstr = po_get_str(ppo);
if (pstr != NULL) {
/* set config file name name */
psz->ext_mkf = pstr;
} else {
return false;
}
}
}
}
/* get base directory (REQUIRED) */
pdir = po_get_str(hash_get(pht, KW_OPT_DIR));
psz->directory = strdup(pdir);
/* get discard list */
ppo = hash_get(pht, KW_OPT_DSC);
if (ppo != NULL) {
psz->discard = po_get_list(ppo);
}
/* get library name list */
ppo = hash_get(pht, KW_OPT_LIB);
if (ppo != NULL) {
da_l = po_get_list(ppo);
if (da_l != NULL) {
for (i = 0 ; i < da_usize(da_l) ; i++) {
/* get lib name */
pstr = da_idx(da_l, i);
/* look for lib cell */
plc = hash_extract(libs, pstr);
if (plc == NULL) {
/* lib cell not found */
return false;
}
/* adds the extracted cell in zone libraries */
if (hash_add(psz->libraries, pstr, plc) == HASH_ADD_FAIL) {
return false;
}
/* set library type flag */
psz->lib_type[plc->type] = true;
}
}
psz->gen_lib = true;
}
/* get recursivity switch (OPTIONAL, false by default) */
ppo = hash_get(pht, KW_OPT_REC);
if (ppo != NULL) {
psz->recursive = po_get_bool(ppo);
}
/* get unique file switch (OPTIONAL, false by default) */
ppo = hash_get(pht, KW_OPT_UNI);
if (ppo != NULL) {
psz->unique = po_get_bool(ppo);
}
/* get extra tags list */
ppo = hash_get(pht, KW_OPT_EXTTAG);
if (ppo != NULL) {
psz->exttags = po_get_list(ppo);
}
return true;
}
/******************
* parse_script() *
***********************************************************************
DESCR
parse script file
IN
cfname : configuration script filename
pcmn : common parser structure
psd : scanning data structure
OUT
boolean (true on success)
***********************************************************************/
bool parse_script(char *cfname, prs_cmn_t *pcmn, scandata *psd) {
FILE *fd;
bool frslt = true;
htable *lcells;
prscell *pcell;
prsdata *pdata;
scn_zone_t *psz;
fd = fopen(cfname, "r");
if (fd == NULL) {
errorf("cannot open '%s' : %s.", cfname, strerror(errno));
return false;
}
/* init of library cells hash table */
lcells = hash_init_adv(32, NULL, (void (*)(void *)) lib_cell_destroy, NULL);
if (lcells == NULL) {
/* XXX errmsg */
return false;
}
/* initialise parsing data structure */
pdata = prsdata_init();
if (pdata == NULL) {
/* XXX errmsg */
return false;
}
if (parse_pmkfile(fd, pdata, kw_scanfile, nbkwsf) == false) {
fclose(fd);
prsdata_destroy(pdata);
errorf("parsing of script file failed.");
return false;
}
fclose(fd);
pcell = pdata->tree->first;
while (pcell != NULL) {
switch(pcell->token) {
case PSC_TOK_DEFLIB :
if (parse_deflib(pcell->data, lcells) == false) {
errorf("parsing of script file failed (token %d).", pcell->token);
prsdata_destroy(pdata);
return false;
}
break;
case PSC_TOK_PMKF :
case PSC_TOK_MAKF :
case PSC_TOK_ZONE :
if (parse_zone_opts(pcmn, pcell->data, lcells) == false) {
errorf("parsing of script file failed (token %d).", pcell->token);
prsdata_destroy(pdata);
return false;
}
/* process current zone */
if (process_zone(pcmn, psd) == false) {
frslt = false;
}
/* free scan zone stuff */
psz = pcmn->data;
hash_destroy(psz->nodes);
scan_zone_destroy(psz);
break;
default :
errorf("parsing of script file failed (unexpected token %d).", pcell->token);
prsdata_destroy(pdata);
return false;
break;
}
pcell = pcell->next;
}
prsdata_destroy(pdata);
return(frslt);
}
/***********
* usage() *
***********************************************************************
DESCR
pmkscan(1) usage
IN
NONE
OUT
NONE
***********************************************************************/
void usage(void) {
fprintf(stderr, "usage: pmkscan [-hlv] [-f file] [path]\n");
}
/**********
* main() *
***********************************************************************
DESCR
main loop.
***********************************************************************/
int main(int argc, char *argv[]) {
bool go_exit = false;
char scfile[PATH_MAX] = PMKSCAN_CONFIG;
int chr;
prs_cmn_t pcmn;
prsdata *pdata = NULL;
scandata sd;
while (go_exit == false) {
chr = getopt(argc, argv, "f:hlv");
switch (chr) {
case -1 :
go_exit = true;
break;
case 'f' :
/* use alternate script file */
strlcpy(scfile, optarg, sizeof(scfile)); /* XXX test !! */
break;
case 'l' :
fp_log = fopen("pmkscan.log", "w");
if (fp_log == NULL) {
/* XXX err msg */
exit(EXIT_FAILURE);
}
break;
case 'v' :
/* display version */
fprintf(stdout, "%s\n", PREMAKE_VERSION);
exit(EXIT_SUCCESS);
break;
case 'h' :
case '?' :
default :
usage();
exit(EXIT_FAILURE);
/* NOTREACHED */
}
}
argc = argc - optind;
argv = argv + optind;
psc_log("PMKSCAN version %s\n\n", NULL, PREMAKE_VERSION);
psc_log("Initializing data ... \n", NULL);
/* init common parser structure */
pcmn.func_ppro = &process_ppro;
pcmn.func_proc = &process_proc_call;
pcmn.func_decl = &process_proc_decl;
pcmn.func_type = &process_type;
pcmn.data = NULL; /* will be updated later */
/* initialise parsing data structure */
pdata = prsdata_init();
if (pdata == NULL) {
errorf("\ncannot initialize prsdata.");
exit(EXIT_FAILURE);
} else {
if (parse_data_file(pdata, &sd) == false) {
/* error message displayed by parse_data_file */
prsdata_destroy(pdata);
exit(EXIT_FAILURE);
}
}
psc_log("Using scanning script '%s'.\n", NULL, scfile);
if (parse_script(scfile, &pcmn, &sd) == false) {
exit(EXIT_FAILURE);
}
prsdata_destroy(pdata);
if (fp_log != NULL) {
fclose(fp_log);
}
return(0);
}
/* vim: set noexpandtab tabstop=4 softtabstop=4 shiftwidth=4: */
syntax highlighted by Code2HTML, v. 0.9.1