/* $Id: pmkscan.c 1970 2007-04-13 21:14:05Z coudercd $ */ /* * Copyright (c) 2003-2006 Damien Couderc * Copyright (c) 2004 Xavier Santolaria * 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 - this will avoid errors */ #include "compat/pmk_sys_types.h" #include #include #include #include #include #include #include #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: */