-
Adam Knapp authored
Change-Id: Iacba53d8499439eba82045c30a1e0f2e0edf16fe Signed-off-by:
Adam Knapp <adam.knapp@sigmatechnology.se>
Adam Knapp authoredChange-Id: Iacba53d8499439eba82045c30a1e0f2e0edf16fe Signed-off-by:
Adam Knapp <adam.knapp@sigmatechnology.se>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
xpather.cc 133.99 KiB
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
*
* Baji, Laszlo
* Balasko, Jeno
* Baranyi, Botond
* Beres, Szabolcs
* Delic, Adam
* Kovacs, Ferenc
* Ormandi, Matyas
* Pandi, Krisztian
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Pandi, Krisztian
*
******************************************************************************/
#include "xpather.h"
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#define LIBXML_SCHEMAS_ENABLED
#include <libxml/xmlschemastypes.h>
#include "../common/memory.h"
#include "vector.hh"
// Do _NOT_ #include "string.hh", it drags in ustring.o, common/Quadruple.o,
// Int.o, ttcn3/PatternString.o, and then the entire AST :(
#include "map.hh"
#include "ProjectGenHelper.hh"
#include "../common/path.h"
#include "ttcn3/ttcn3_preparser.h"
#include "asn1/asn1_preparser.h"
// in makefile.c
void ERROR (const char *fmt, ...);
void WARNING(const char *fmt, ...);
void NOTIFY (const char *fmt, ...);
void DEBUG (const char *fmt, ...);
// for vector and map
void fatal_error(const char * filename, int lineno, const char * fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4), __noreturn__));
void fatal_error(const char * filename, int lineno, const char * fmt, ...)
{
fputs(filename, stderr);
fprintf(stderr, ":%d: ", lineno);
va_list va;
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
abort();
}
static ProjectGenHelper& projGenHelper = ProjectGenHelper::Instance();
/// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
xmlXPathObjectPtr run_xpath(xmlXPathContextPtr xpathCtx, const char *xpathExpr)
{
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(
(const xmlChar *)xpathExpr, xpathCtx);
if(xpathObj == NULL) {
fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
return 0;
}
return xpathObj;
}
// RAII classes
class XmlDoc {
public:
explicit XmlDoc(xmlDocPtr p) : doc_(p) {}
~XmlDoc() {
if (doc_ != NULL) xmlFreeDoc(doc_);
}
operator xmlDocPtr() const { return doc_; }
private:
xmlDocPtr doc_;
};
class XPathContext {
public:
explicit XPathContext(xmlXPathContextPtr c) : ctx_(c) {}
~XPathContext() {
if (ctx_ != NULL) xmlXPathFreeContext(ctx_);
}
operator xmlXPathContextPtr() const { return ctx_; }
private:
xmlXPathContextPtr ctx_;
};
class XPathObject {
public:
explicit XPathObject(xmlXPathObjectPtr o) : xpo_(o) {}
~XPathObject() {
if (xpo_ != NULL) xmlXPathFreeObject(xpo_);
}
operator xmlXPathObjectPtr() const { return xpo_; }
xmlXPathObjectPtr operator->() const { return xpo_; }
private:
xmlXPathObjectPtr xpo_;
};
//------------------------------------------------------------------
/// compare-by-content wrapper of a plain C string
struct cstring {
explicit cstring(const char *s) : str(s) {}
void destroy() const;
operator const char*() const { return str; }
protected:
const char *str;
friend boolean operator<(const cstring& l, const cstring& r);
friend boolean operator==(const cstring& l, const cstring& r);
};
void cstring::destroy() const {
Free(const_cast<char*>(str)); // assumes valid pointer or NULL
}
boolean operator<(const cstring& l, const cstring& r) {
return strcmp(l.str, r.str) < 0;
}
boolean operator==(const cstring& l, const cstring& r) {
return strcmp(l.str, r.str) == 0;
}
/// RAII for C string
struct autostring : public cstring {
/// Constructor; takes over ownership
explicit autostring(const char *s = 0) : cstring(s) {}
~autostring() {
// He who can destroy a thing, controls that thing -- Paul Muad'Dib
Free(const_cast<char*>(str)); // assumes valid pointer or NULL
}
/// %Assignment; takes over ownership
const autostring& operator=(const char *s) {
Free(const_cast<char*>(str)); // assumes valid pointer or NULL
str = s;
return *this;
}
/// Relinquish ownership
const char *extract() {
const char *retval = str;
str = 0;
return retval;
}
private:
autostring(const autostring&);
autostring& operator=(const autostring&);
};
bool validate_tpd(const XmlDoc& xml_doc, const char* tpd_file_name, const char* xsd_file_name)
{
xmlLineNumbersDefault(1);
xmlSchemaParserCtxtPtr ctxt = xmlSchemaNewParserCtxt(xsd_file_name);
if (ctxt==NULL) {
ERROR("Unable to create xsd context for xsd file `%s'", xsd_file_name);
return false;
}
xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc)fprintf, (xmlSchemaValidityWarningFunc)fprintf, stderr);
xmlSchemaPtr schema = xmlSchemaParse(ctxt);
if (schema==NULL) {
ERROR("Unable to parse xsd file `%s'", xsd_file_name);
xmlSchemaFreeParserCtxt(ctxt);
return false;
}
xmlSchemaValidCtxtPtr xsd = xmlSchemaNewValidCtxt(schema);
if (xsd==NULL) {
ERROR("Schema validation error for xsd file `%s'", xsd_file_name);
xmlSchemaFree(schema);
xmlSchemaFreeParserCtxt(ctxt);
return false;
}
xmlSchemaSetValidErrors(xsd, (xmlSchemaValidityErrorFunc) fprintf, (xmlSchemaValidityWarningFunc) fprintf, stderr);
int ret = xmlSchemaValidateDoc(xsd, xml_doc);
xmlSchemaFreeValidCtxt(xsd);
xmlSchemaFree(schema);
xmlSchemaFreeParserCtxt(ctxt);
xmlSchemaCleanupTypes();
if (ret==0) {
return true; // successful validation
} else if (ret>0) {
ERROR("TPD file `%s' is invalid according to schema `%s'", tpd_file_name, xsd_file_name);
return false;
} else {
ERROR("TPD validation of `%s' generated an internal error in libxml2", tpd_file_name);
return false;
}
}
/** Extract a boolean value from the XML, if it exists otherwise flag is unchanged
*
* @param xpathCtx XPath context object
* @param actcfg name of the active configuration
* @param option name of the value
* @param flag pointer to the variable to receive the value
*/
void xsdbool2boolean(const XPathContext& xpathCtx, const char *actcfg,
const char *option, boolean* flag)
{
char *xpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/%s[text()='true']",
actcfg, option);
XPathObject xpathObj(run_xpath(xpathCtx, xpath));
Free(xpath);
if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
*flag = TRUE;
}
}
extern "C" string_list* getExternalLibs(const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
if (!proj) return NULL;
std::vector<const char*> externalLibs;
projGenHelper.getExternalLibs(externalLibs);
if (0 == externalLibs.size()) return NULL;
struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
struct string_list* last_elem = head;
struct string_list* tail = head;
for (size_t i = 0; i < externalLibs.size(); ++i) {
tail = last_elem;
last_elem->str = mcopystr(externalLibs[i]);
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
}
Free(last_elem);
tail->next = NULL;
return head;
}
extern "C" string_list* getExternalLibPaths(const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
if (!proj) return NULL;
std::vector<const char*> externalLibs;
projGenHelper.getExternalLibSearchPaths(externalLibs);
if (0 == externalLibs.size()) return NULL;
struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
struct string_list* last_elem = head;
struct string_list* tail = head;
for (size_t i = 0; i < externalLibs.size(); ++i) {
tail = last_elem;
last_elem->str = mcopystr(externalLibs[i]);
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
}
Free(last_elem);
tail->next = NULL;
return head;
}
extern "C" string_list* getRefWorkingDirs(const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
if (!proj) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
struct string_list* last_elem = head;
struct string_list* tail = head;
last_elem->str = NULL;
last_elem->next = NULL;
for (size_t i = 0; i < proj->numOfRefProjWorkingDirs(); ++i) {
tail = last_elem;
last_elem->str = mcopystr(proj->getRefProjWorkingDir(i).c_str());
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
}
Free(last_elem);
tail->next = NULL;
return head;
}
extern "C" string2_list* getLinkerLibs(const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
if (1 == projGenHelper.numOfProjects() || 0 == projGenHelper.numOfLibs()){
return NULL; //no library
}
ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
struct string2_list* head = (struct string2_list*)Malloc(sizeof(struct string2_list));
struct string2_list* last_elem = head;
struct string2_list* tail = head;
last_elem->next = NULL;
last_elem->str1 = NULL;
last_elem->str2 = NULL;
for (std::map<std::string, ProjectDescriptor>::const_iterator it = projGenHelper.getHead();
it != projGenHelper.getEnd(); ++it) {
if ((it->second).isLibrary()) {
if (!(it->second).getLinkingStrategy() &&
!projLib->hasLinkerLibTo((it->second).getProjectName())) { // static linked library
continue;
}
std::string relPath = projLib->setRelativePathTo((it->second).getProjectAbsWorkingDir());
if (relPath == std::string(".")) {
continue; // the relpath shows to itself
}
tail = last_elem;
last_elem->str1 = mcopystr(relPath.c_str());
last_elem->str2 = mcopystr((it->second).getTargetExecName().c_str());
last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
last_elem = last_elem->next;
}
}
tail->next = NULL;
Free(last_elem);
if (head->str1 && head->str2)
return head;
else
return NULL;
}
extern "C" const char* getLibFromProject(const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* lib = projGenHelper.getTargetOfProject(projName);
if (lib) return lib->getTargetExecName().c_str();
return NULL;
}
extern "C" void erase_libs(void) {
projGenHelper.cleanUp();
}
extern "C" void print_libs(void) {
projGenHelper.print();
}
extern "C" boolean hasSubProject(const char* projName) {
if (!projGenHelper.getZflag()) return FALSE;
if (projGenHelper.getHflag())
return static_cast<boolean>(projGenHelper.hasReferencedProject());
else if(std::string(projName) == projGenHelper.getToplevelProjectName())
return static_cast<boolean>(projGenHelper.hasReferencedProject());
else
return FALSE;
}
extern "C" boolean hasExternalLibrary(const char* libName, const char* projName) {
if (!projGenHelper.getZflag()) return FALSE;
ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
if (projLib && projLib->hasLinkerLib(libName))
return TRUE;
else
return FALSE;
}
extern "C" boolean isTopLevelExecutable(const char* projName) {
if (!projGenHelper.getZflag()) return false;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
if (projGenHelper.getToplevelProjectName() != std::string(projName)) return FALSE;
if (proj && proj->isLibrary())
return FALSE;
else
return TRUE;
}
extern "C" boolean isDynamicLibrary(const char* key) {
if (!projGenHelper.getZflag()) return false;
ProjectDescriptor* proj = projGenHelper.getProjectDescriptor(key);
if (proj) return proj->getLinkingStrategy();
FATAL_ERROR("Library \"%s\" was not found", key);
return false;
}
extern "C" const char* getTPDFileName(const char* projName) {
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
if (proj) return proj->getTPDFileName().c_str();
FATAL_ERROR("TPD file name to project \"%s\" was not found", projName);
}
extern "C" const char* getPathToRootDir(const char* projName) {
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
const char* rootDir = projGenHelper.getRootDirOS(projName).c_str();
if (proj && rootDir) {
return rootDir;
}
FATAL_ERROR("Project \"%s\": no relative path was found to top directory at OS level.", projName);
}
extern "C" const char* findLibraryPath(const char* libraryName, const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName);
if (!libLib) return NULL;
std::string str = projLib->setRelativePathTo(libLib->getProjectAbsWorkingDir());
size_t refIndex = projLib->getLibSearchPathIndex(libLib->getProjectName());
if (refIndex > projLib->numOfLibSearchPaths()) return NULL;
projLib->setLibSearchPath(refIndex, str);
return projLib->getLibSearchPath(libLib->getProjectName());
}
extern "C" const char* findLibraryName(const char* libraryName, const char* projName)
{
if (!projGenHelper.getZflag()) return NULL;
ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName);
if (!libLib) return NULL;
for (size_t i = 0; i < projLib->numOfReferencedProjects(); ++i) {
const std:: string refProjName = projLib->getReferencedProject(i);
ProjectDescriptor* refLib = projGenHelper.getTargetOfProject(refProjName.c_str());
if (refLib->getTargetExecName() == std::string(libraryName))
return libraryName;
}
return NULL;
}
extern "C" boolean isTtcn3ModuleInLibrary(const char* moduleName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isTtcn3ModuleInLibrary(moduleName);
}
extern "C" boolean isAsn1ModuleInLibrary(const char* moduleName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isAsn1ModuleInLibrary(moduleName);
}
extern "C" boolean isSourceFileInLibrary(const char* fileName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isSourceFileInLibrary(fileName);
}
extern "C" boolean isHeaderFileInLibrary(const char* fileName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isHeaderFileInLibrary(fileName);
}
extern "C" boolean isTtcnPPFileInLibrary(const char* fileName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isTtcnPPFileInLibrary(fileName);
}
extern "C" boolean isXSDModuleInLibrary(const char* fileName)
{
if (!projGenHelper.getZflag()) return FALSE;
return (boolean)projGenHelper.isXSDModuleInLibrary(fileName);
}
extern "C" boolean buildObjects(const char* projName, boolean add_referenced)
{
if (!projGenHelper.getZflag()) return FALSE;
if (projGenHelper.getHflag()) return FALSE;
if (add_referenced) return FALSE;
ProjectDescriptor* desc =projGenHelper.getTargetOfProject(projName);
if (desc && desc->isLibrary()) return FALSE;
return TRUE;
}
void append_to_library_list (const char* prjName,
const XPathContext& xpathCtx,
const char *actcfg)
{
if (!projGenHelper.getZflag()) return;
char *exeXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/targetExecutable/text()",
actcfg);
XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
Free(exeXpath);
if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
autostring target_exe_dir(get_dir_from_path(target_executable));
autostring target_exe_file(get_file_from_path(target_executable));
std::string lib_name;
lib_name = target_exe_file;
ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(prjName);
if (projDesc) {
projDesc->setTargetExecName(lib_name.c_str());
}
}
}
// data structures and functions to manage excluded folders/files
static map<cstring, const char> excluded_files;
boolean is_excluded_file(const cstring& path, const char* project) {
if (!excluded_files.has_key(path)) return false;
const char* proj = excluded_files[path];
if (0 == strcmp(project, proj)) return true;
return false;
}
static vector<const char> excluded_folders;
// Unfortunately, when "docs" is excluded, we need to drop
// files in "docs/", "docs/pdf/", "docs/txt/", "docs/txt/old/" etc;
// so it's not as simple as using a map :(
/** Checks whether a file is under an excluded folder
*
* @param path (relative) path of the file
* @return true if file is excluded, false otherwise
*/
boolean is_excluded_folder(const char *path) {
boolean answer = FALSE;
size_t pathlen = strlen(path);
for (size_t i = 0, end = excluded_folders.size(); i < end; ++i) {
const char *xdir = excluded_folders[i];
size_t xdlen = strlen(xdir);
if (pathlen > xdlen && path[xdlen] == '/') {
// we may have a winner
if ((answer = !strncmp(path, xdir, xdlen))) break;
}
}
return answer;
}
// How do you treat a raw info? You cook it, of course!
// Returns a newly allocated string.
char *cook(const char *raw, const map<cstring, const char>& path_vars)
{
const char *slash = strchr(raw, '/');
if (!slash) { // Pretend that the slash is at the end of the string.
slash = raw + strlen(raw);
}
// Assume that a path variable reference is the first (or only) component
// of the path: ROOT in "ROOT/etc/issue".
autostring prefix(mcopystrn(raw, slash - raw));
if (path_vars.has_key(prefix)) {
char *cooked = mcopystr(path_vars[prefix]);
bool ends_with_slash = cooked[strlen(cooked)-1] == '/';
if (ends_with_slash && *slash == '/') {
// Avoid paths with two slashes at the start; Cygwin thinks it's UNC
++slash;
}
// If there was no '/' (only the path variable reference e.g "ROOT")
// then slash points to a null byte and the mputstr is a no-op.
cooked = mputstr(cooked, slash);
return cooked;
}
// If the path variable could not be substituted,
// return (a copy of) the original.
return mcopystr(raw);
}
void replacechar(char** content) {
std::string s= *content;
size_t found = 0;
while ((found = s.find('['))!= std::string::npos){
s.replace(found,1, "${");
}
while ((found = s.find(']')) != std::string::npos){
s.replace(found,1, "}");
}
*content = mcopystr(s.c_str());
}
/** Determines the suffix (i.e. the character sequence following the last dot)
* of file or path name \a file_name. NULL pointer is returned if \a file_name
* does not contain any dot character or the last character of it is a dot.
* The suffix is not copied, the returned pointer points to the tail of
* \a file_name. */
const char *get_suffix(const char *file_name)
{
size_t last_dot = (size_t)-1;
size_t i;
for (i = 0; file_name[i] != '\0'; i++)
if (file_name[i] == '.') last_dot = i;
if (last_dot == (size_t)-1 || file_name[last_dot + 1] == '\0') return NULL;
else return file_name + last_dot + 1;
}
int is_xsd_module(const char *file_name, char **module_name) {
const char * extension = get_suffix(file_name);
if (extension == NULL) {
return 0;
}
if (strcmp(extension, "xsd") != 0) {
return 0;
}
if (module_name != NULL) *module_name = NULL;
FILE *fp;
char line[1024];
char *command = NULL;
char *ttcn3_dir = getenv("TTCN3_DIR");
command = mputprintf(command, "%s%sxsd2ttcn -q -n %s",
ttcn3_dir != NULL ? ttcn3_dir : "",
ttcn3_dir != NULL ? "/bin/" : "",
file_name);
fp = popen(command, "r");
Free(command);
if (fp == NULL) {
ERROR("Could not get the module names of the XSD modules");
return 0;
}
while (fgets(line, sizeof(line)-1, fp) != NULL) {
*module_name = mputstr(*module_name, line);
}
int rv= pclose(fp);
if (rv > 0) {
return 0;
}
return *module_name != NULL;
}
static void clear_seen_tpd_files(map<cstring, int>& seen_tpd_files) {
for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
const cstring& key = seen_tpd_files.get_nth_key(i);
int *elem = seen_tpd_files.get_nth_elem(i);
key.destroy();
delete elem;
}
seen_tpd_files.clear();
}
const char* get_act_config(struct string2_list* cfg, const char* project_name) {
while (cfg && cfg->str1 && project_name) {
if (!strcmp(cfg->str1, project_name)) return cfg->str2;
cfg = cfg->next;
}
return NULL;
}
void free_string_list(struct string_list* act_elem)
{
while (act_elem) {
struct string_list* next_elem = act_elem->next;
Free(act_elem->str);
Free(act_elem);
act_elem = next_elem;
}
}
void free_string2_list(struct string2_list* act_elem)
{
while (act_elem) {
struct string2_list* next_elem = act_elem->next;
Free(act_elem->str1);
Free(act_elem->str2);
Free(act_elem);
act_elem = next_elem;
}
}
void free_config_list(struct config_list* act_elem) {
while (act_elem) {
struct config_list* next_elem = act_elem->next;
Free(act_elem->str1);
Free(act_elem->str2);
Free(act_elem);
act_elem = next_elem;
}
}
void free_config_struct(struct config_struct* act_elem) {
while (act_elem) {
struct config_struct* next_elem = act_elem->next;
Free(act_elem->project_name);
Free(act_elem->project_conf);
free_string_list(act_elem->dependencies);
free_string2_list(act_elem->requirements);
free_string_list(act_elem->children);
Free(act_elem);
act_elem = next_elem;
}
}
// Initialize a config_struct to NULL-s
static void config_struct_init(struct config_struct* const list) {
list->project_name = list->project_conf = NULL;
list->is_active = FALSE;
list->dependencies = (struct string_list*)Malloc(sizeof(struct string_list));
list->dependencies->str = NULL;
list->dependencies->next = NULL;
list->requirements = (struct string2_list*)Malloc(sizeof(struct string2_list));
list->requirements->str1 = NULL;
list->requirements->str2 = NULL;
list->requirements->next = NULL;
list->children = (struct string_list*)Malloc(sizeof(struct string_list));
list->children->str = NULL;
list->children->next = NULL;
list->processed = FALSE;
list->next = NULL;
}
// This function fills up the dependencies field of the config_structs
// using the children fields.
static void config_struct_fillup_deps(struct config_struct* const list) {
struct config_struct* last = list;
while (last && last->project_name != NULL) { // Go through the projects
struct config_struct* lastest = list;
while (lastest && lastest->project_name != NULL) { // Go through the projects again n^2 complexity
struct string_list* lastest_child = lastest->children;
while (lastest_child && lastest_child->str != NULL) {
if (strcmp(last->project_name, lastest_child->str) == 0) { // If a project is a child of another project
// Add the other project to the project's dependencies
// But first check if it is already in the dependencies
boolean already_in = FALSE;
struct string_list* last_dep = last->dependencies;
while (last_dep && last_dep->str != NULL) {
if (strcmp(last_dep->str, lastest->project_name) == 0) {
already_in = TRUE;
break;
}
last_dep = last_dep->next;
}
if (already_in == FALSE) {
last_dep->str = mcopystr(lastest->project_name);
struct string_list* last_dep_next = (struct string_list*)Malloc(sizeof(string_list));
last_dep_next->str = NULL;
last_dep_next->next = NULL;
last_dep->next = last_dep_next;
break;
}
}
lastest_child = lastest_child->next;
}
lastest = lastest->next;
}
last = last->next;
}
}
// This function inserts project_name project's project_config configuration
// into the required configurations. This function can detect errors.
// If an error is detected FALSE is returned, otherwise TRUE.
static boolean insert_to_required_config(const struct config_struct* all_configs, const char* project_name, const char* project_config, struct string2_list* const required_configs) {
boolean found_project = FALSE;
boolean found_config = FALSE;
boolean result = TRUE;
//Check that it is a valid configuration for a valid project
const struct config_struct* last = all_configs;
while(last && last->project_name != NULL && last->project_conf != NULL) {
if (strcmp(last->project_name, project_name) == 0) {
found_project = TRUE;
if (strcmp(last->project_conf, project_config) == 0) {
found_config = TRUE;
break;
}
}
last = last->next;
}
// If the project or the configuration is not found
if (found_project == FALSE || found_config == FALSE) {
result = FALSE;
}
// Check if the project is already in the required configurations
// or if the project is present with a different configuration
boolean already_in = FALSE;
struct string2_list* last_required_config = required_configs;
while (last_required_config && last_required_config->str1 != NULL && last_required_config->str2 != NULL) {
// If we have a record of this project
if (strcmp(last_required_config->str1, project_name) == 0) {
if (strcmp(last_required_config->str2, project_config) == 0) {
// This project configuration is already in the required_configs
already_in = TRUE;
} else {
// This project configuration is different than it is in the required_configs
result = FALSE;
}
}
last_required_config = last_required_config->next;
}
// If the project's configuration is not already present in the required
// configs then we insert it. We insert it even when the result is FALSE.
if (last_required_config && already_in == FALSE) {
// Make copies of strings
last_required_config->str1 = mcopystr(project_name);
last_required_config->str2 = mcopystr(project_config);
// Init next required configuration
struct string2_list* last_required_config_next = (struct string2_list*)Malloc(sizeof(struct string2_list));
last_required_config_next->str1 = NULL;
last_required_config_next->str2 = NULL;
last_required_config_next->next = NULL;
last_required_config->next = last_required_config_next;
}
return result;
}
// Inserts project_name project with project_config configuration to the tmp_configs
// Return TRUE if the configuration is inserted
// Returns FALSE if the configuration is not inserted
// Returns 2 if the configuration is already in the tmp_configs (still inserted)
static boolean insert_to_tmp_config(struct config_list* const tmp_configs, const char* project_name, const char* project_config, const boolean is_active) {
//First we check that it is a valid configuration for a valid project
boolean found_project = FALSE;
boolean found_config = FALSE;
boolean active = FALSE;
boolean result = TRUE;
//Check if we have the same project with same configuration in the tmp_configs
struct config_list* last = tmp_configs;
while(last && last->str1 != NULL && last->str2 != NULL) {
if (strcmp(last->str1, project_name) == 0) {
found_project = TRUE;
active = last->is_active;
if (strcmp(last->str2, project_config) == 0) {
found_config = TRUE;
break;
}
}
last = last->next;
}
//The case of same project with same configuration
if (found_project == TRUE && found_config == TRUE) {
result = 2;
// The case of same project different configuration and the configuration
// is not default
} else if(found_project == TRUE && active == FALSE) {
return FALSE;
}
// Go to the end of list
while (last->next) {
last = last->next;
}
// Insert new config into the tmp_configs
last->str1 = mcopystr(project_name);
last->str2 = mcopystr(project_config);
last->is_active = is_active;
last->next = (struct config_list*)Malloc(sizeof(config_list));
last->next->str1 = NULL;
last->next->str2 = NULL;
last->next->is_active = FALSE;
last->next->next = NULL;
return result;
}
// Removes the last element from the tmp_configs
static void remove_from_tmp_config(struct config_list* const tmp_configs, const char* /*project_name*/, const char* /*project_config*/) {
struct config_list* last = tmp_configs;
while (last->next && last->next->next != NULL) {
last = last->next;
}
Free(last->str1);
Free(last->str2);
last->str1 = NULL;
last->str2 = NULL;
last->is_active = FALSE;
Free(last->next);
last->next = NULL;
}
// This function detects a circle originating from start_project.
// act_project is the next project which might be in the circle
// needed_in is a project that is needed to be inside the circle
// list is a temporary list which contains the elements of circle
static boolean is_circular_dep(const struct config_struct* all_configs, const char* start_project, const char* act_project, const char* needed_in, struct string_list** list) {
if (*list == NULL) {
*list = (struct string_list*)Malloc(sizeof(string_list));
(*list)->str = mcopystr(start_project);
(*list)->next = (struct string_list*)Malloc(sizeof(string_list));
(*list)->next->str = NULL;
(*list)->next->next = NULL;
}
//Circle detection
struct string_list* last_list = *list;
while (last_list && last_list->str != NULL) {
struct string_list* last_list2 = last_list;
while (last_list2 && last_list2->str != NULL) {
// If the pointers are different but the project name is the same
if (last_list != last_list2 && strcmp(last_list->str, last_list2->str) == 0) {
// We look for the circle which starts from the start_project
if (strcmp(last_list->str, start_project) != 0) {
return FALSE;
} else {
// Check if needed_in is inside the circle
while (last_list != last_list2) {
if (needed_in != NULL && strcmp(last_list->str, needed_in) == 0) {
return TRUE;
}
last_list = last_list->next;
}
return FALSE;
}
}
last_list2 = last_list2->next;
}
last_list = last_list->next;
}
// Insert next element and call recursively for all the referenced projects
const struct config_struct* last = all_configs;
while (last && last->project_name) {
//Find an act_project configuration
if (strcmp(last->project_name, act_project) == 0) {
// Go through its children
struct string_list* children = last->children;
while (children && children->str != NULL) {
// Insert child into list
last_list->str = mcopystr(children->str);
last_list->next = (struct string_list*)Malloc(sizeof(string_list));
last_list->next->str = NULL;
last_list->next->next = NULL;
// Call recursively
if (is_circular_dep(all_configs, start_project, children->str, needed_in, list) == TRUE) {
return TRUE;
}
// Remove child
last_list = *list;
while(last_list && last_list->next != NULL && last_list->next->next != NULL) {
last_list = last_list->next;
}
Free(last_list->str);
Free(last_list->next);
last_list->str = NULL;
last_list->next = NULL;
children = children->next;
}
}
last = last->next;
}
return FALSE;
}
// check if project_name project does not exists todo
// Project config == NULL means that we need to analyse the children of the project, todo why
// This function analyses project_name project to get the required configuration
// of this project.
// project_config may be NULL. It is not null when we are not certain of the
// project_name project's configuration.
// tmp_configs acts like a stack. It contains the history calls of anal_child. It
// is used to detect circles therefore prevents infinite recursions.
static boolean analyse_child(struct config_struct* const all_configs, const char* project_name, const char* project_config, struct string2_list* const required_configs, struct config_list* const tmp_configs) {
boolean result = TRUE;
const char* act_config = get_act_config(required_configs, project_name);
// If the required configuration is known of project_name project
if (act_config != NULL) {
struct config_struct* tmp = all_configs;
// Get the project_name's act_config config_struct (tmp holds it)
while (tmp && tmp->project_name != NULL && tmp->project_conf != NULL) {
if (strcmp(tmp->project_name, project_name) == 0 && strcmp(tmp->project_conf, act_config) == 0) {
break;
}
tmp = tmp->next;
}
if (tmp->processed == TRUE) {
// We already processed this project there is nothing to be done
return result;
}
// Set the project to processed
tmp->processed = TRUE;
// Get the last (empty) required configuration
struct string2_list* last_required_config = required_configs;
while (last_required_config->next != NULL) {
last_required_config = last_required_config->next;
}
// Insert all required config of project_name project's act_config configuration
struct string2_list* last_proj_config = tmp->requirements;
while (last_proj_config && last_proj_config->str1 != NULL && last_proj_config->str2 != NULL) {
insert_to_required_config(all_configs, last_proj_config->str1, last_proj_config->str2, required_configs);
last_proj_config = last_proj_config->next;
}
// Analyse the children of this project too.
insert_to_tmp_config(tmp_configs, project_name, act_config, TRUE);
struct string_list* last_child = tmp->children;
while (last_child && last_child->str != NULL) {
result = analyse_child(all_configs, last_child->str, NULL, required_configs, tmp_configs);
if (result == FALSE) return result;
last_child = last_child->next;
}
remove_from_tmp_config(tmp_configs, project_name, act_config);
} else {
// The required configuration of the project_name project is unknown
boolean found = FALSE; // True if someone requires a configuration about project_name project
boolean is_active = FALSE;
// Go through every required configuration to check if someone requires
// something about project_name project.
struct config_struct* last = all_configs;
while (last && last->requirements != NULL) {
struct string2_list* req_config = last->requirements;
while (req_config && req_config->str1 != NULL && req_config->str2 != NULL) {
// If someone requires something about project_name project
if (strcmp(req_config->str1, project_name) == 0) {
const struct config_struct* tmp = all_configs;
if (project_config == NULL) {
// Get the active configuration of project_name project
while (tmp && tmp->project_name != NULL && tmp->project_conf != NULL) {
if (strcmp(tmp->project_name, project_name) == 0 && tmp->is_active == TRUE) {
act_config = tmp->project_conf;
is_active = TRUE;
break;
}
tmp = tmp->next;
}
} else {
act_config = project_config;
}
found = TRUE;
// Insert the project_name with its active configuration
result = insert_to_tmp_config(tmp_configs, project_name, act_config, is_active);
if (result == FALSE) {
return FALSE;
} else if (result == 2) { // result is 2 if a circle is detected (this will cause error later)
result = insert_to_required_config(all_configs, project_name, act_config, required_configs);
if (result == FALSE) return result;
}
// Analyse the project that requires something about project_name project
result = analyse_child(all_configs, last->project_name, last->project_conf, required_configs, tmp_configs);
remove_from_tmp_config(tmp_configs, project_name, act_config);
// If some errors happened during the analysis of last->project_conf project
if (result == FALSE) {
req_config = req_config->next;
continue;
}
// If we still don't know anything about the project_name project's configuration
if (get_act_config(required_configs, project_name) == NULL) {
// Go to the next required config
req_config = req_config->next;
continue;
} else {
found = TRUE;
}
// Get the project_name's act_config config_struct (tmp holds it)
tmp = all_configs;
while (tmp && tmp->project_name != NULL && tmp->project_conf != NULL) {
if (strcmp(tmp->project_name, project_name) == 0 && strcmp(tmp->project_conf, act_config) == 0) {
break;
}
tmp = tmp->next;
}
// We know for sure that the project_name project's configuration is
// act_config, so we insert all the required configs of project_name
// project's act_config configuration
struct string2_list* last_proj_config = tmp->requirements;
while (last_proj_config && last_proj_config->str1 != NULL && last_proj_config->str2 != NULL) {
result = insert_to_required_config(all_configs, last_proj_config->str1, last_proj_config->str2, required_configs);
if (result == FALSE) return result;
last_proj_config = last_proj_config->next;
}
insert_to_tmp_config(tmp_configs, project_name, act_config, is_active);
// Analyze referenced projects of project_name project
struct string_list* last_child = tmp->children;
while (last_child && last_child->str != NULL) {
result = analyse_child(all_configs, last_child->str, NULL, required_configs, tmp_configs);
if (result == FALSE) return result;
last_child = last_child->next;
}
remove_from_tmp_config(tmp_configs, tmp->project_name, tmp->project_conf);
}
req_config = req_config->next;
}
last = last->next;
}
// No one said anything about this project's configuration or we still don't know the configuration
if (found == FALSE || get_act_config(required_configs, project_name) == NULL) {
//Get the active configuration of this project
last = all_configs;
while (last && last->project_name != NULL && last->project_conf != NULL) {
if (strcmp(last->project_name, project_name) == 0 && last->is_active) {
act_config = last->project_conf;
break;
}
last = last->next;
}
if (last->processed == TRUE) {
// We already processed this project
return TRUE;
}
last->processed = TRUE;
// Insert the active configuration to the required_configs
result = insert_to_required_config(all_configs, project_name, act_config, required_configs);
if (result == FALSE) return result;
//Insert the project requirements of the project_name project's active configuration
struct string2_list* last_proj_config = last->requirements;
while (last_proj_config && last_proj_config->str1 != NULL && last_proj_config->str2 != NULL) {
struct config_list* tmp_tmp = tmp_configs;
// Detect circle in all_configs, which is started from last_proj_config->str1 and
// project_name is an element of the circle
struct string_list* list = NULL;
boolean circular = is_circular_dep(all_configs, last_proj_config->str1, last_proj_config->str1, project_name, &list);
boolean need_circular_error = FALSE;
// Find the last_proj_config->str1 project in the circle, and
// determine if it has parent projects other than that are in the circle
if (circular) {
// Find the config struct of last_proj_config->str1
struct config_struct* tmp2 = all_configs;
while (tmp2 && tmp2->project_name != NULL) {
if (strcmp(tmp2->project_name, last_proj_config->str1) == 0) {
break;
}
tmp2 = tmp2->next;
}
if (list && tmp2 && tmp2->dependencies != NULL) {
struct string_list* deps = tmp2->dependencies;
while (deps && deps->str != NULL) {
struct string_list* tmp_list = list;
boolean tmp_error = FALSE;
while (tmp_list && tmp_list->str != NULL) {
if (strcmp(tmp_list->str, deps->str) == 0) {
tmp_error = TRUE;
break;
}
tmp_list = tmp_list->next;
}
if (tmp_error == FALSE) {
need_circular_error = TRUE;
break;
}
deps = deps->next;
}
}
}
free_string_list(list);
// Go through the tmp_configs to check inconsistency
while (tmp_tmp && tmp_tmp->str1 != NULL && tmp_tmp->str2 != NULL) {
if (strcmp(tmp_tmp->str1, last_proj_config->str1) == 0 &&
strcmp(tmp_tmp->str2, last_proj_config->str2) != 0 &&
circular && need_circular_error) {
// Insert the configuration. This will cause an error later.
insert_to_required_config(all_configs, tmp_tmp->str1, tmp_tmp->str2, required_configs);
result = FALSE;
}
tmp_tmp = tmp_tmp->next;
}
// Important to && the result at the end. If the result is FALSE from the
// while cycle above, then it must remain FALSE
result = insert_to_required_config(all_configs, last_proj_config->str1, last_proj_config->str2, required_configs) && result;
if (result == FALSE) return result;
last_proj_config = last_proj_config->next;
}
insert_to_tmp_config(tmp_configs, project_name, act_config, last->is_active);
// Analyse children of the project_name project
struct string_list* last_child = last->children;
while (last_child && last_child->str != NULL) {
result = analyse_child(all_configs, last_child->str, NULL, required_configs, tmp_configs);
if (result == FALSE) return result;
last_child = last_child->next;
}
remove_from_tmp_config(tmp_configs, project_name, act_config);
}
}
return result;
}
static tpd_result config_struct_get_required_configs(struct config_struct* const all_configs, struct string2_list* const required_configs, struct config_list** tmp_configs) {
// Init tmp_configs, which will be used to detect circularity
*tmp_configs = (struct config_list*)Malloc(sizeof(config_list));
(*tmp_configs)->str1 = NULL;
(*tmp_configs)->str2 = NULL;
(*tmp_configs)->is_active = FALSE;
(*tmp_configs)->next = NULL;
// Fill up dependencies of the configurations
config_struct_fillup_deps(all_configs);
struct config_struct* last = all_configs;
// The top level project is always the first project and we need the active configuration of the project
while (last) {
if (last->project_name != NULL && all_configs->project_name != NULL) {
if (strcmp(all_configs->project_name, last->project_name) == 0 && last->is_active == TRUE && last->processed == FALSE) {
boolean result = TRUE;
// Insert the top level project's active configuration to the required configs.
result = insert_to_required_config(all_configs, last->project_name, last->project_conf, required_configs);
if (result == FALSE) return TPD_FAILED;
insert_to_tmp_config(*tmp_configs, last->project_name, last->project_conf, TRUE);
// last variable holds the top level project's active configuration which needed to be analyzed
// Insert every required config of the top level project active configuration
struct string2_list* last_proj_config = last->requirements;
while (last_proj_config && last_proj_config->str1 != NULL && last_proj_config->str2 != NULL) { // todo ezek a null cuccok mindenhova, every param should not be null
struct string_list* children = last->children;
// This if allows that a top level project can require an other project's configuration
// without referencing it.
if (children->str != NULL || strcmp(last_proj_config->str1, last->project_name) == 0) {
result = insert_to_required_config(all_configs, last_proj_config->str1, last_proj_config->str2, required_configs);
if (result == FALSE) return TPD_FAILED;
}
last_proj_config = last_proj_config->next;
}
last->processed = TRUE;
//Analyze the referenced project of the top level project
struct string_list* last_child = last->children;
while (last_child && last_child->str != NULL) {
result = analyse_child(all_configs, last_child->str, NULL, required_configs, *tmp_configs); // todo check if everywhere is handled
if (result == FALSE) return TPD_FAILED;
last_child = last_child->next;
}
remove_from_tmp_config(*tmp_configs, last->project_name, last->project_conf);
break; // No more needed
}
}
last = last->next;
}
return TPD_SUCCESS;
}
static tpd_result process_tpd_internal(const char **p_tpd_name, char* tpdName, const char *actcfg,
const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
int *p_optind, char **p_ets_name, char **p_project_name,
boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
struct string_list* prep_defines, struct string_list* prep_undefines, char **p_csmode, boolean *p_quflag, boolean* p_dsflag,
char** cxxcompiler, char** optlevel, char** optflags, char** linkerOptions, boolean* semantic_check_only, boolean* disable_attibute_validation,
boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, boolean* p_doerflag,
boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, boolean *p_Eflag, boolean* p_nflag, boolean* p_Nflag,
boolean* p_diflag, boolean* p_enable_legacy_encoding, boolean* p_disable_userinfo, boolean* p_realtime_features, boolean* p_oop_features,
boolean* p_charstring_compat, struct string_list* solspeclibs, struct string_list* sol8speclibs,
struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
struct string_list* linkerlibs, struct string_list* additionalObjects, struct string_list* linkerlibsearchp, boolean Vflag, boolean Dflag,
boolean *p_Zflag, boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
struct string2_list* run_command_list, map<cstring, int>& seen_tpd_files, struct string2_list* required_configs, struct string_list** profiled_file_list,
const char **search_paths, size_t n_search_paths, char** makefileScript, struct config_struct * const all_configs);
extern "C" tpd_result process_tpd(const char **p_tpd_name, const char *actcfg,
const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
int *p_optind, char **p_ets_name, char **p_project_name,
boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
struct string_list* prep_defines, struct string_list* prep_undefines, char **p_csmode, boolean *p_quflag, boolean* p_dsflag,
char** cxxcompiler, char** optlevel, char** optflags, char** linkerOptions, boolean* semantic_check_only, boolean* disable_attibute_validation,
boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, boolean* p_doerflag,
boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, boolean* p_Eflag, boolean* p_nflag, boolean* p_Nflag,
boolean* p_diflag, boolean* p_enable_legacy_encoding, boolean* p_disable_userinfo, boolean* p_realtime_features, boolean* p_oop_features,
boolean* p_charstring_compat, struct string_list* solspeclibs, struct string_list* sol8speclibs,
struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag,
boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
struct string2_list* run_command_list, struct string2_list* required_configs, struct string_list** profiled_file_list,
const char **search_paths, size_t n_search_paths, char** makefileScript) {
map<cstring, int> seen_tpd_files;
char *tpdName = NULL;
projGenHelper.setZflag(*p_Zflag);
projGenHelper.setWflag(prefix_workdir);
projGenHelper.setHflag(*p_Hflag);
struct config_struct* all_configs = (struct config_struct*)Malloc(sizeof(struct config_struct));
config_struct_init(all_configs);
// The first round only collects the configurations about the tpd-s into the
// all_configs variable. It does not do anything else.
tpd_result success = process_tpd_internal(p_tpd_name, tpdName,
actcfg, file_list_path, p_argc, p_argv, p_free_argv, p_optind, p_ets_name, p_project_name,
p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
p_Rflag, p_lflag, p_mflag, p_Pflag,
p_Lflag, recursive, force_overwrite, gen_only_top_level,
output_file, abs_work_dir_p, sub_project_dirs,
program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes,
ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines,
prep_undefines, p_csmode, p_quflag, p_dsflag, cxxcompiler,
optlevel, optflags, linkerOptions, semantic_check_only, disable_attibute_validation,
p_dbflag, p_drflag, p_dtflag, p_dxflag, p_djflag, p_doerflag,
p_fxflag, p_doflag, p_gfflag, p_lnflag, p_isflag,
p_asflag, p_swflag, p_Yflag, p_Mflag, p_Eflag, p_nflag, p_Nflag,
p_diflag, p_enable_legacy_encoding, p_disable_userinfo,
p_realtime_features, p_oop_features, p_charstring_compat, solspeclibs, sol8speclibs,
linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep,
linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag, p_Zflag,
p_Hflag, generatorCommandOutput, target_placement_list, prefix_workdir,
run_command_list, seen_tpd_files, required_configs, profiled_file_list,
search_paths, n_search_paths, makefileScript, all_configs);
if (success == TPD_SUCCESS) {
struct config_list* tmp_configs = NULL;
config_struct_get_required_configs(all_configs, required_configs, &tmp_configs);
free_config_list(tmp_configs);
free_config_struct(all_configs);
all_configs = NULL;
// In the second round every configuration is known for every project in the
// optimal case. In the not optimal case errors are produced.
// This round does get the information from the tpd to generate the makefile.
success = process_tpd_internal(p_tpd_name, tpdName,
actcfg, file_list_path, p_argc, p_argv, p_free_argv, p_optind, p_ets_name, p_project_name,
p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
p_Rflag, p_lflag, p_mflag, p_Pflag,
p_Lflag, recursive, force_overwrite, gen_only_top_level,
output_file, abs_work_dir_p, sub_project_dirs,
program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes,
ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines,
prep_undefines, p_csmode, p_quflag, p_dsflag, cxxcompiler,
optlevel, optflags, linkerOptions, semantic_check_only, disable_attibute_validation,
p_dbflag, p_drflag, p_dtflag, p_dxflag, p_djflag, p_doerflag,
p_fxflag, p_doflag, p_gfflag, p_lnflag, p_isflag,
p_asflag, p_swflag, p_Yflag, p_Mflag, p_Eflag, p_nflag, p_Nflag,
p_diflag, p_enable_legacy_encoding, p_disable_userinfo,
p_realtime_features, p_oop_features, p_charstring_compat, solspeclibs, sol8speclibs,
linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep,
linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag, p_Zflag,
p_Hflag, generatorCommandOutput, target_placement_list, prefix_workdir,
run_command_list, seen_tpd_files, required_configs, profiled_file_list,
search_paths, n_search_paths, makefileScript, all_configs);
} else {
free_config_struct(all_configs);
all_configs = NULL;
}
if (TPD_FAILED == success){
goto failure;
}
if (false == projGenHelper.sanityCheck()) {
fprintf (stderr, "makefilegen exits\n");
goto failure;
}
projGenHelper.generateRefProjectWorkingDirsTo(*p_project_name);
for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
const cstring& key = seen_tpd_files.get_nth_key(i);
int *elem = seen_tpd_files.get_nth_elem(i);
key.destroy();
delete elem;
}
seen_tpd_files.clear();
return TPD_SUCCESS;
failure:
/* free everything before exiting */
free_string_list(sub_project_dirs);
free_string_list(ttcn3_prep_includes);
free_string_list(ttcn3_prep_defines);
free_string_list(ttcn3_prep_undefines);
free_string_list(prep_includes);
free_string_list(prep_defines);
free_string_list(prep_undefines);
free_string_list(solspeclibs);
free_string_list(sol8speclibs);
free_string_list(linuxspeclibs);
free_string_list(freebsdspeclibs);
free_string_list(win32speclibs);
free_string_list(linkerlibs);
free_string_list(additionalObjects);
free_string_list(linkerlibsearchp);
free_string_list(*profiled_file_list);
Free(search_paths);
Free(*generatorCommandOutput);
free_string2_list(run_command_list);
free_string2_list(create_symlink_list);
free_string2_list(target_placement_list);
free_string2_list(required_configs);
Free(*makefileScript);
Free(*p_project_name);
Free(*abs_work_dir_p);
Free(*p_ets_name);
Free(*cxxcompiler);
Free(*optlevel);
Free(*optflags);
Free(*linkerOptions);
Free(*ttcn3prep);
if (*p_free_argv) {
for (int E = 0; E < *p_argc; ++E) Free((*p_argv)[E]);
Free(*p_argv);
}
for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
const cstring& key = seen_tpd_files.get_nth_key(i);
int *elem = seen_tpd_files.get_nth_elem(i);
key.destroy();
delete elem;
}
seen_tpd_files.clear();
return TPD_FAILED;
}
// optind is the index of the next element of argv to be processed.
// Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
// seen already, or TPD_FAILED.
//
// Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
// (argv[], ets_name, other_files[], output_file) are allocated on the heap
// and need to be freed. On input, these strings point into argv.
// process_tpd() may alter these strings; new values will be on the heap.
// If process_tpd() preserves the content of such a string (e.g. ets_name),
// it must nevertheless make a copy on the heap via mcopystr().
static tpd_result process_tpd_internal(const char **p_tpd_name, char *tpdName, const char *actcfg,
const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
int *p_optind, char **p_ets_name, char **p_project_name,
boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
struct string_list* prep_defines, struct string_list* prep_undefines, char **p_csmode, boolean *p_quflag, boolean* p_dsflag,
char** cxxcompiler, char** optlevel, char** optflags, char** linkerOptions, boolean* semantic_check_only, boolean* disable_attibute_validation,
boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, boolean* p_doerflag,
boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, boolean* p_Eflag, boolean* p_nflag, boolean* p_Nflag,
boolean* p_diflag, boolean* p_enable_legacy_encoding, boolean* p_disable_userinfo, boolean* p_realtime_features, boolean* p_oop_features,
boolean* p_charstring_compat, struct string_list* solspeclibs, struct string_list* sol8speclibs,
struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag,
boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
struct string2_list* run_command_list, map<cstring, int>& seen_tpd_files, struct string2_list* required_configs, struct string_list** profiled_file_list,
const char **search_paths, size_t n_search_paths, char** makefileScript, struct config_struct * const all_configs)
{
tpd_result result = TPD_SUCCESS;
// read-only non-pointer aliases
//char** const& local_argv = *p_argv;
int const& local_argc = *p_argc;
int const& local_optind = *p_optind;
*abs_work_dir_p = NULL;
const boolean get_config_mode = all_configs != NULL;
assert(local_optind >= 2 // at least '-ttpd_name' must be in the args
|| local_optind == 0); // if called for a referenced project
assert(local_argc >= local_optind);
autostring tpd_dir(get_dir_from_path(*p_tpd_name));
autostring abs_tpd_dir(get_absolute_dir(tpd_dir, NULL, FALSE));
struct stat buf;
//Only referenced project, when first try is failed, and when not absolute path
if(0 == local_optind && *p_tpd_name != NULL && stat(*p_tpd_name, &buf) && tpdName != NULL) {
//Find the first search_path that has the tpd
for(size_t i = 0; i<n_search_paths; i++) {
boolean need_slash = search_paths[i][strlen(search_paths[i]) - 1] != '/';
NOTIFY("Cannot find %s, trying with %s%s%s\n", *p_tpd_name, search_paths[i], need_slash ? "/" : "", tpdName);
//Create path
char * prefixed_file_path = (char*)Malloc((strlen(search_paths[i]) + strlen(tpdName) + 1 + need_slash) * sizeof(char));
strcpy(prefixed_file_path, search_paths[i]);
if(need_slash) {
strcat(prefixed_file_path, "/");
}
strcat(prefixed_file_path, tpdName);
tpd_dir = get_dir_from_path(prefixed_file_path);
abs_tpd_dir = get_absolute_dir(tpd_dir, NULL, FALSE);
if(!stat(prefixed_file_path, &buf)){
//Ok, tpd found
Free(const_cast<char*>(*p_tpd_name));
*p_tpd_name = prefixed_file_path;
NOTIFY("TPD with name %s found at %s.", tpdName, search_paths[i]);
break;
} else {
//tpd not found, continue search
abs_tpd_dir = NULL;
Free(prefixed_file_path);
}
}
//Error if tpd is not found in either search paths
if(NULL == (const char*)abs_tpd_dir) {
//Only write out the name in the error message (without .tpd)
tpdName[strlen(tpdName)-4] ='\0';
ERROR("Unable to find ReferencedProject with name: %s", (const char*)tpdName);
return TPD_FAILED;
}
}
if (NULL == (const char*)abs_tpd_dir) {
ERROR("absolute TPD directory could not be retrieved from %s", (const char*)tpd_dir);
return TPD_FAILED;
}
autostring tpd_filename(get_file_from_path(*p_tpd_name));
autostring abs_tpd_name(compose_path_name(abs_tpd_dir, tpd_filename));
if (local_optind == 0) {
Free(const_cast<char*>(*p_tpd_name));
*p_tpd_name = mcopystr((const char*)abs_tpd_name);
}
if (seen_tpd_files.has_key(abs_tpd_name)) {
++*seen_tpd_files[abs_tpd_name];
return TPD_SKIPPED; // nothing to do
}
else {
if (recursive && !prefix_workdir) {
// check that this tpd file is not inside a directory of another tpd file
for (size_t i = 0; i < seen_tpd_files.size(); ++i) {
const cstring& other_tpd_name = seen_tpd_files.get_nth_key(i);
autostring other_tpd_dir(get_dir_from_path((const char*)other_tpd_name));
if (strcmp((const char*)abs_tpd_dir,(const char*)other_tpd_dir)==0) {
ERROR("TPD files `%s' and `%s' are in the same directory! Use the `-W' option.", (const char*)abs_tpd_name, (const char*)other_tpd_name);
return TPD_FAILED;
}
}
}
// mcopystr makes another copy for the map
seen_tpd_files.add(cstring(mcopystr(abs_tpd_name)), new int(1));
}
vector<char> base_files; // values Malloc'd but we pass them to the caller
XmlDoc doc(xmlParseFile(*p_tpd_name));
if (doc == NULL) {
fprintf(stderr, "Error: unable to parse file \"%s\"\n", *p_tpd_name);
return TPD_FAILED;
}
if (!Vflag && get_config_mode) {
// try schema validation if tpd schema file was found
bool tpd_is_valid = false;
const char* ttcn3_dir = getenv("TTCN3_DIR");
if (ttcn3_dir) {
size_t ttcn3_dir_len = strlen(ttcn3_dir);
bool ends_with_slash = (ttcn3_dir_len>0) && (ttcn3_dir[ttcn3_dir_len - 1]=='/');
expstring_t xsd_file_name = mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir, ends_with_slash?"":"/");
autostring xsd_file_name_as(xsd_file_name);
if (get_path_status(xsd_file_name)==PS_FILE) {
if (validate_tpd(doc, *p_tpd_name, xsd_file_name)) {
tpd_is_valid = true;
NOTIFY("TPD file `%s' validated successfully with schema file `%s'", *p_tpd_name, xsd_file_name);
}
} else {
ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name);
}
} else {
ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
}
if (!tpd_is_valid) {
return TPD_FAILED;
}
}
// Source files.
// Key is projectRelativePath, value is relativeURI or rawURI.
map<cstring, const char> files; // values Malloc'd
map<cstring, const char> folders; // values Malloc'd
// NOTE! files and folders must be local variables of process_tpd.
// This is because the keys (not the values) are owned by the XmlDoc.
map<cstring, const char> path_vars;
autostring workdir;
autostring abs_workdir;
XPathContext xpathCtx(xmlXPathNewContext(doc));
if (xpathCtx == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
return TPD_FAILED;
}
/////////////////////////////////////////////////////////////////////////////
{
char *projectNameXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()");
XPathObject projectNameObj(run_xpath(xpathCtx, projectNameXpath));
Free(projectNameXpath);
if (projectNameObj->nodesetval && projectNameObj->nodesetval->nodeNr > 0) {
if (*p_project_name != NULL) {
Free(*p_project_name);
}
*p_project_name = mcopystr((const char*)projectNameObj->nodesetval->nodeTab[0]->content);
projGenHelper.addTarget(*p_project_name);
projGenHelper.setToplevelProjectName(*p_project_name);
ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
if (projDesc) projDesc->setProjectAbsTpdDir((const char*)abs_tpd_dir);
projGenHelper.insertAndCheckProjectName((const char*)abs_tpd_name, *p_project_name);
}
}
/////////////////////////////////////////////////////////////////////////////
if (!actcfg && !get_config_mode) {
actcfg = get_act_config(required_configs, *p_project_name);
}
if (actcfg == NULL) {
// Find out the active config
XPathObject activeConfig(run_xpath(xpathCtx,
"/TITAN_Project_File_Information/ActiveConfiguration/text()"));
if (activeConfig->nodesetval && activeConfig->nodesetval->nodeNr == 1) {
// there is one node
actcfg = (const char*)activeConfig->nodesetval->nodeTab[0]->content;
}
}
if (actcfg == NULL) {
ERROR("Can not find the active build configuration.");
for (size_t i = 0; i < folders.size(); ++i) {
Free(const_cast<char*>(folders.get_nth_elem(i)));
}
folders.clear();
return TPD_FAILED;
}
{ // check if the active configuration exists
expstring_t xpathActCfg= mprintf(
"/TITAN_Project_File_Information/Configurations/"
"Configuration[@name='%s']/text()", actcfg);
XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfg));
Free(xpathActCfg);
xmlNodeSetPtr nodes = theConfigEx->nodesetval;
if (nodes == NULL) {
ERROR("The active build configuration named '%s' of project '%s' does not exist",
actcfg, *p_project_name);
for (size_t i = 0; i < folders.size(); ++i) {
Free(const_cast<char*>(folders.get_nth_elem(i)));
}
folders.clear();
return TPD_FAILED;
}
}
if (!get_config_mode) {
{
struct string2_list* last_elem = required_configs;
// To ensure that the first elem is checked too if last_elem->next is null
while (last_elem && last_elem->str1 != NULL && last_elem->str2 != NULL) {
if (!strcmp(last_elem->str1, *p_project_name) && strcmp(last_elem->str2, actcfg)) {
{ // check if the other configuration exists
expstring_t xpathActCfg= mprintf(
"/TITAN_Project_File_Information/Configurations/"
"Configuration[@name='%s']/text()", last_elem->str2);
XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfg));
Free(xpathActCfg);
xmlNodeSetPtr nodes = theConfigEx->nodesetval;
if (nodes == NULL) {
ERROR("The active build configuration named '%s' of project '%s' does not exist",
last_elem->str2, *p_project_name);
for (size_t i = 0; i < folders.size(); ++i) {
Free(const_cast<char*>(folders.get_nth_elem(i)));
}
folders.clear();
return TPD_FAILED;
}
}
ERROR("Required configuration is inconsistent or circular : Project '%s' cannot have 2 "
"different configuration '%s' and '%s'",
last_elem->str1, actcfg, last_elem->str2);
for (size_t i = 0; i < folders.size(); ++i) {
Free(const_cast<char*>(folders.get_nth_elem(i)));
}
folders.clear();
return TPD_FAILED;
}
last_elem = last_elem->next;
}
}
// Collect path variables
{
XPathObject pathsObj(run_xpath(xpathCtx,
"/TITAN_Project_File_Information/PathVariables/PathVariable"));
xmlNodeSetPtr nodes = pathsObj->nodesetval;
const char *name = 0, *value = 0;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// nodes->nodeTab[i]->name === "PathVariable"
for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "name")) {
name = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "value")) {
value = (const char*)attr->children->content;
}
else {
WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
}
} // next attribute
if (name && value) path_vars.add(cstring(name), value);
else ERROR("A PathVariable must have both name and value");
} // next PathVariable
}
// Collect folders
{
XPathObject foldersObj(run_xpath(xpathCtx,
"/TITAN_Project_File_Information/Folders/FolderResource"));
xmlNodeSetPtr nodes = foldersObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// nodes->nodeTab[i]->name === "FolderResource"
const char *uri = 0, *path = 0, *raw = 0;
// projectRelativePath is the path as it appears in Project Explorer (illusion)
// relativeURI is the actual location, relative to the project root (reality)
// rawURI is present if the relative path can not be calculated
//
// Theoretically these attributes could be in any order, loop over them
for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "projectRelativePath")) {
path = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "relativeURI")) {
uri = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "rawURI")) {
raw = (const char*)attr->children->content;
}
else {
WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
}
} // next attribute
if (path == NULL) {
ERROR("A FolderResource must have a projectRelativePath");
continue;
}
if (uri == NULL && raw == NULL) {
ERROR("A FolderResource must have either relativeURI or rawURI");
continue;
}
// relativeURI wins over rawURI
folders.add(cstring(path), uri ? mcopystr(uri) : cook(raw, path_vars));
// TODO uri: cut "file:", complain on anything else
} // next FolderResource
}
// working directory stuff
{
const char* workdirFromTpd = "bin"; // default value
char *workdirXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
actcfg);
XPathObject workdirObj(run_xpath(xpathCtx, workdirXpath));
Free(workdirXpath);
if (workdirObj->nodesetval && workdirObj->nodesetval->nodeNr > 0) {
workdirFromTpd = (const char*)workdirObj->nodesetval->nodeTab[0]->content;
}
if (prefix_workdir) { // the working directory is: prjNameStr + "_" + workdirFromTpd
const char* prjNameStr = "unnamedproject";
XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
}
workdir = mprintf("%s_%s", prjNameStr, workdirFromTpd);
} else {
workdir = mcopystr(workdirFromTpd);
}
}
if (!folders.has_key(workdir)) {
// Maybe the tpd was saved with the option "No info about work dir"
folders.add(workdir, mcopystr(workdir)); // fake it
}
const char *real_workdir = folders[workdir]; // This is relative to the location of the tpd file
excluded_folders.add(real_workdir); // excluded by convention
autostring proj_abs_workdir;
// If -D flag was specified then we ignore the workdir
// in the TPD (the current dir is considered the work dir).
if (!Dflag) {
bool hasWorkDir = false;
// if the working directory does not exist create it
autostring saved_work_dir(get_working_dir());
if (set_working_dir(abs_tpd_dir)) {
ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir);
} else {
switch (get_path_status(real_workdir)) {
case PS_FILE:
ERROR("Cannot create working directory `%s' in project directory `%s' because a file with the same name exists", (const char*)abs_tpd_dir, real_workdir);
break;
case PS_DIRECTORY:
// already exists
hasWorkDir = true;
break;
default:
if (recursive || local_argc != 0) { // we only want to create workdir if necessary
fprintf(stderr, "Working directory `%s' in project `%s' does not exist, trying to create it...\n",
real_workdir, (const char*)abs_tpd_dir);
int rv = mkdir(real_workdir, 0755);
if (rv) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno));
else printf("Working directory created\n");
hasWorkDir = true;
}
}
}
if (local_argc==0) { // if not top level
set_working_dir(saved_work_dir); // restore working directory
} else { // if top level
set_working_dir(real_workdir); // go into the working dir
}
if (hasWorkDir) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
*abs_work_dir_p = get_absolute_dir(real_workdir, abs_tpd_dir, TRUE);
abs_workdir = (mcopystr(*abs_work_dir_p));
proj_abs_workdir = mcopystr(*abs_work_dir_p);
}
}
if (Dflag) { // the path to subproject working dir is needed to find the linkerlibsearchpath
proj_abs_workdir = compose_path_name(abs_tpd_dir, real_workdir);
}
ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
if (projDesc) {
projDesc->setProjectAbsWorkingDir((const char*)proj_abs_workdir);
projDesc->setProjectWorkingDir(real_workdir);
projDesc->setTPDFileName(*p_tpd_name);
}
/////////////////////////////////////////////////////////////////////////////
// Gather the excluded folders in the active config
{
expstring_t xpathActCfgPaths = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
// This was the selection criterium, we need to go up and down for the actual information
"/parent::*/parent::*/FolderPath/text()",
actcfg);
XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
Free(xpathActCfgPaths);
xmlNodeSetPtr nodes = theConfigEx->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
excluded_folders.add((const char*)nodes->nodeTab[i]->content);
}
}
// Gather individual excluded files in the active config
{
expstring_t xpathActCfgPaths = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
"/parent::*/parent::*/FilePath/text()",
actcfg);
XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
Free(xpathActCfgPaths);
xmlNodeSetPtr nodes = theConfigEx->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
xmlNodePtr curnode = nodes->nodeTab[i];
cstring aa((const char*)curnode->content);
if (!excluded_files.has_key(aa)) {
excluded_files.add(aa, *p_project_name);
} else {
WARNING("Multiple exclusion of file %s", (const char*)curnode->content);
}
}
}
// Collect files; filter out excluded ones
{
XPathObject filesObj(run_xpath(xpathCtx,
"/TITAN_Project_File_Information/Files/FileResource"));
xmlNodeSetPtr nodes = filesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// nodes->nodeTab[i]->name === "FileResource"
const char *uri = 0, *path = 0, *raw = 0;
// projectRelativePath is the path as it appears in Project Explorer (illusion)
// relativeURI is the actual location, relative to the project root (reality)
// rawURI is present if the relative path can not be calculated
//
// Theoretically these attributes could be in any order, loop over them
for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "projectRelativePath")) {
path = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "relativeURI")) {
uri = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "rawURI")) {
raw = (const char*)attr->children->content;
}
else {
WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
}
} // next attribute
if (path == NULL) {
ERROR("A FileResource must have a projectRelativePath");
continue;
}
if (uri == NULL && raw == NULL) {
ERROR("A FileResource must have either relativeURI or rawURI");
continue;
}
cstring cpath(path);
if (!is_excluded_file(cpath, *p_project_name) && !is_excluded_folder(path)) {
// relativeURI wins over rawURI
char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
if (files.has_key(cpath)) {
ERROR("A FileResource %s must be unique!", (const char*)cpath);
}
else {
bool drop = false;
const char* file_path = ruri;
expstring_t rel_file_dir = get_dir_from_path(file_path);
expstring_t file_name = get_file_from_path(file_path);
expstring_t abs_dir_path = get_absolute_dir(rel_file_dir, abs_tpd_dir, TRUE);
expstring_t abs_file_name = compose_path_name(abs_dir_path, file_name);
if (abs_file_name != NULL) {
if (get_path_status(abs_file_name) == PS_FILE) {
FILE *fp = fopen(abs_file_name, "r");
if (fp != NULL) {
char* ttcn3_module_name;
if (is_ttcn3_module(abs_file_name, fp, &ttcn3_module_name)) {
projGenHelper.addTtcn3ModuleToProject(*p_project_name, ttcn3_module_name);
}
Free(ttcn3_module_name);
char* asn1_module_name;
if (is_asn1_module(abs_file_name, fp, &asn1_module_name)) {
projGenHelper.addAsn1ModuleToProject(*p_project_name, asn1_module_name);
}
Free(asn1_module_name);
char* xsd_module_name = NULL;
if (is_xsd_module(abs_file_name, &xsd_module_name)) {
projGenHelper.addXSDModuleToProject(*p_project_name, xsd_module_name);
}
Free(xsd_module_name);
if (projGenHelper.isCPPSourceFile(file_name)) {
projGenHelper.addUserSourceToProject(*p_project_name, file_name);
}
if (projGenHelper.isCPPHeaderFile(file_name)) {
projGenHelper.addUserHeaderToProject(*p_project_name, file_name);
}
if (projGenHelper.isTtcnPPFile(file_name)) {
projGenHelper.addTtcnPPToProject(*p_project_name, file_name);
}
}
fclose(fp);
}else {
drop = true;
ERROR("%s does not exist", abs_file_name);
}
}
if(abs_dir_path != NULL && !drop){
files.add(cpath, ruri); // relativeURI to the TPD location
}else {
result = TPD_FAILED;
}
{ // set the *preprocess value if .ttcnpp file was found
const size_t ttcnpp_extension_len = 7; // ".ttcnpp"
const size_t ruri_len = strlen(ruri);
if ( ruri_len>ttcnpp_extension_len && strcmp(ruri+(ruri_len-ttcnpp_extension_len),".ttcnpp")==0 ) {
*preprocess = TRUE;
}
}
Free(rel_file_dir);
Free(file_name);
Free(abs_dir_path);
Free(abs_file_name);
}
}
} // next FileResource
}
// Gather the code splitting mode from the active configuration
{
expstring_t xpathActCfgCodeSplitting = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"//ProjectProperties/MakefileSettings/codeSplitting/text()",
actcfg);
XPathObject codeSplittingObj(run_xpath(xpathCtx, xpathActCfgCodeSplitting));
Free(xpathActCfgCodeSplitting);
if (codeSplittingObj->nodesetval && codeSplittingObj->nodesetval->nodeNr > 0) {
const char* content = (const char*)codeSplittingObj->nodesetval->nodeTab[0]->content;
if (local_argc != 0) { // top level project
// Get the code splitting without thinking
*p_csmode = mcopystr(content);
} else if (*p_csmode == NULL && strcmp(content, "none") != 0) { // todo config in error message?
ERROR("The top level project does not have code splitting set, but the `%s' project has `%s' code splitting set.",
*p_project_name, content);
} else if (*p_csmode != NULL && strcmp(content, *p_csmode)) {
ERROR("Code splitting must be the same. Top level project has `%s', `%s' project has `%s' code splitting set.",
*p_csmode, *p_project_name, content);
}
} else if (*p_csmode != NULL && strcmp(*p_csmode, "none") != 0) {
ERROR("The top level project have `%s' code splitting set, but the `%s' project has none.",
*p_csmode, *p_project_name);
}
}
// Check options
xsdbool2boolean(xpathCtx, actcfg, "useAbsolutePath", p_aflag);
xsdbool2boolean(xpathCtx, actcfg, "GNUMake", p_gflag);
if (*p_Zflag) *p_lflag = FALSE;
xsdbool2boolean(xpathCtx, actcfg, "dynamicLinking", p_lflag);
xsdbool2boolean(xpathCtx, actcfg, "functiontestRuntime", p_Rflag);
xsdbool2boolean(xpathCtx, actcfg, "singleMode", p_sflag);
xsdbool2boolean(xpathCtx, actcfg, "quietly", p_quflag);
xsdbool2boolean(xpathCtx, actcfg, "disableSubtypeChecking", p_dsflag);
xsdbool2boolean(xpathCtx, actcfg, "semanticCheckOnly", semantic_check_only);
xsdbool2boolean(xpathCtx, actcfg, "disableAttributeValidation", disable_attibute_validation);
xsdbool2boolean(xpathCtx, actcfg, "disableBER", p_dbflag);
xsdbool2boolean(xpathCtx, actcfg, "disableRAW", p_drflag);
xsdbool2boolean(xpathCtx, actcfg, "disableTEXT", p_dtflag);
xsdbool2boolean(xpathCtx, actcfg, "disableXER", p_dxflag);
xsdbool2boolean(xpathCtx, actcfg, "disableJSON", p_djflag);
xsdbool2boolean(xpathCtx, actcfg, "disableOER", p_doerflag);
xsdbool2boolean(xpathCtx, actcfg, "forceXERinASN.1", p_fxflag);
xsdbool2boolean(xpathCtx, actcfg, "defaultasOmit", p_doflag);
xsdbool2boolean(xpathCtx, actcfg, "gccMessageFormat", p_gfflag);
xsdbool2boolean(xpathCtx, actcfg, "lineNumbersOnlyInMessages", p_lnflag);
xsdbool2boolean(xpathCtx, actcfg, "includeSourceInfo", p_isflag);
xsdbool2boolean(xpathCtx, actcfg, "addSourceLineInfo", p_asflag);
xsdbool2boolean(xpathCtx, actcfg, "suppressWarnings", p_swflag);
xsdbool2boolean(xpathCtx, actcfg, "outParamBoundness", p_Yflag); //not documented, obsolete
xsdbool2boolean(xpathCtx, actcfg, "forceOldFuncOutParHandling", p_Yflag);
xsdbool2boolean(xpathCtx, actcfg, "omitInValueList", p_Mflag);
xsdbool2boolean(xpathCtx, actcfg, "warningsForBadVariants", p_Eflag);
xsdbool2boolean(xpathCtx, actcfg, "activateDebugger", p_nflag);
xsdbool2boolean(xpathCtx, actcfg, "disablePredefinedExternalFolder", p_diflag);
xsdbool2boolean(xpathCtx, actcfg, "ignoreUntaggedOnTopLevelUnion", p_Nflag);
xsdbool2boolean(xpathCtx, actcfg, "enableLegacyEncoding", p_enable_legacy_encoding);
xsdbool2boolean(xpathCtx, actcfg, "disableUserInformation", p_disable_userinfo);
xsdbool2boolean(xpathCtx, actcfg, "enableRealtimeTesting", p_realtime_features);
xsdbool2boolean(xpathCtx, actcfg, "enableOOP", p_oop_features);
xsdbool2boolean(xpathCtx, actcfg, "charstringCompat", p_charstring_compat);
projDesc = projGenHelper.getTargetOfProject(*p_project_name);
if (projDesc) projDesc->setLinkingStrategy(*p_lflag);
// Extract the "incremental dependencies" option
{
boolean incremental_deps = TRUE;
xsdbool2boolean(xpathCtx, actcfg, "incrementalDependencyRefresh", &incremental_deps);
// For makefilegen, "Use GNU make" implies incremental deps by default,
// unless explicitly disabled by "use makedepend" (a.k.a. mflag).
// For Eclipse, incremental deps must be explicitly specified,
// even if GNU make is being used.
if (incremental_deps) {
if( !(*p_gflag) ) {
WARNING("Incremental dependency ordered but it requires gnu make");
}
}
else {
if (*p_gflag) {
// GNU make but no incremental deps
*p_mflag = true;
}
}
}
// Extract the makefileScript only for top level
// In the recursive case the subsequent makefile calls will process the
// makefileScript
if (local_argc != 0)
{
char *makefileScriptXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/LocalBuildSettings/MakefileScript/text()",
actcfg);
XPathObject makefileScriptObj(run_xpath(xpathCtx, makefileScriptXpath));
Free(makefileScriptXpath);
if (makefileScriptObj->nodesetval && makefileScriptObj->nodesetval->nodeNr > 0) {
const char* file_path = (const char*)makefileScriptObj->nodesetval->nodeTab[0]->content;
expstring_t rel_file_dir = get_dir_from_path(file_path);
expstring_t file_name = get_file_from_path(file_path);
expstring_t abs_dir_path = get_absolute_dir(rel_file_dir, abs_tpd_dir, TRUE);
*makefileScript = compose_path_name(abs_dir_path, file_name);
Free(rel_file_dir);
Free(file_name);
Free(abs_dir_path);
}
}
// Extract the default target option
// if it is not defined as a command line argument
if (!(*p_Lflag)) {
expstring_t defTargetXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/defaultTarget/text()",
actcfg);
XPathObject defTargetObj(run_xpath(xpathCtx, defTargetXpath));
Free(defTargetXpath);
if (defTargetObj->nodesetval && defTargetObj->nodesetval->nodeNr > 0) {
const char* content = (const char*)defTargetObj->nodesetval->nodeTab[0]->content;
if (!strcmp(content, "library")) {
*p_Lflag = true;
} else if (!strcmp(content, "executable")) {
*p_Lflag = false;
} else {
ERROR("Unknown default target: '%s'."
" The available targets are: 'executable', 'library'", content);
}
}
ProjectDescriptor* projDescr = projGenHelper.getTargetOfProject(*p_project_name);
if (projDescr) projDescr->setLibrary(*p_Lflag);
}
// Executable name (don't care unless top-level invocation)
if (local_argc != 0)
{
char *exeXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/targetExecutable/text()",
actcfg);
XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
Free(exeXpath);
if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
autostring target_exe_dir(get_dir_from_path(target_executable));
autostring target_exe_file(get_file_from_path(target_executable));
if (target_exe_dir!=NULL) { // if it's not only a file name
if (get_path_status(target_exe_dir)==PS_NONEXISTENT) {
if (strcmp(real_workdir,target_exe_dir)!=0) {
WARNING("Provided targetExecutable directory `%s' does not exist, only file name `%s' will be used", (const char*)target_exe_dir, (const char*)target_exe_file);
}
target_executable = target_exe_file;
}
}
if (!*p_ets_name) { // Command line will win
*p_ets_name = mcopystr(target_executable);
}
}
}
// create an xml element for the currently processed project
if (prj_graph_fp) {
const char* prjNameStr = "???";
XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
}
autostring tpd_rel_dir(get_relative_dir(tpd_dir, NULL));
autostring tpd_rel_path(compose_path_name(tpd_rel_dir, (const char*)tpd_filename));
fprintf(prj_graph_fp, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr, (const char*)tpd_rel_path);
XPathObject subprojects(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
xmlNodeSetPtr nodes = subprojects->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
const char* refd_name = "???";
if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
refd_name = (const char*)nodes->nodeTab[i]->children->content;
}
fprintf(prj_graph_fp, "<reference name=\"%s\"/>\n", refd_name);
}
fprintf(prj_graph_fp, "</project>\n");
}
// Tpd part of the MakefileSettings
{
//TTCN3preprocessorIncludes
char *preincludeXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
actcfg);
XPathObject preincludeObj(run_xpath(xpathCtx, preincludeXpath));
Free(preincludeXpath);
xmlNodeSetPtr nodes = preincludeObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (ttcn3_prep_includes) {
// go to last element
struct string_list* last_elem = ttcn3_prep_includes;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)preincludeObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//TTCN3preprocessorDefines
char *ttcn3predefinesXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
actcfg);
XPathObject ttcn3predefinesObj(run_xpath(xpathCtx, ttcn3predefinesXpath));
Free(ttcn3predefinesXpath);
xmlNodeSetPtr nodes = ttcn3predefinesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (ttcn3_prep_defines) {
// go to last element
struct string_list* last_elem = ttcn3_prep_defines;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
const char* content = (const char*)ttcn3predefinesObj->nodesetval->nodeTab[i]->content;
last_elem->str = mcopystr(content);
}
}
}
{
//TTCN3preprocessorUnDefines
char *ttcn3preUndefinesXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()",
actcfg);
XPathObject ttcn3preUndefinesObj(run_xpath(xpathCtx, ttcn3preUndefinesXpath));
Free(ttcn3preUndefinesXpath);
xmlNodeSetPtr nodes = ttcn3preUndefinesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (ttcn3_prep_undefines) {
// go to last element
struct string_list* last_elem = ttcn3_prep_undefines;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
const char* content = (const char*)ttcn3preUndefinesObj->nodesetval->nodeTab[i]->content;
last_elem->str = mcopystr(content);
}
}
}
{
//preprocessorIncludes
char *preincludesXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
actcfg);
XPathObject preincludesObj(run_xpath(xpathCtx, preincludesXpath));
Free(preincludesXpath);
xmlNodeSetPtr nodes = preincludesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (prep_includes) {
// go to last element
struct string_list* last_elem = prep_includes;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)preincludesObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//preprocessorDefines
char *predefinesXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
actcfg);
XPathObject predefinesObj(run_xpath(xpathCtx, predefinesXpath));
Free(predefinesXpath);
xmlNodeSetPtr nodes = predefinesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (prep_defines) {
// go to last element
struct string_list* last_elem = prep_defines;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
const char* content = (const char*)predefinesObj->nodesetval->nodeTab[i]->content;
last_elem->str = mcopystr(content);
}
}
}
{
//preprocessorUnDefines
char *preUndefinesXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()",
actcfg);
XPathObject preUndefinesObj(run_xpath(xpathCtx, preUndefinesXpath));
Free(preUndefinesXpath);
xmlNodeSetPtr nodes = preUndefinesObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (prep_undefines) {
// go to last element
struct string_list* last_elem = prep_undefines;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
const char* content = (const char*)preUndefinesObj->nodesetval->nodeTab[i]->content;
last_elem->str = mcopystr(content);
}
}
}
{
char *cxxCompilerXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/CxxCompiler/text()",
actcfg);
XPathObject cxxCompilerObj(run_xpath(xpathCtx, cxxCompilerXpath));
Free(cxxCompilerXpath);
xmlNodeSetPtr nodes = cxxCompilerObj->nodesetval;
if (nodes) {
*cxxcompiler = mcopystr((const char*)cxxCompilerObj->nodesetval->nodeTab[0]->content);
}
}
{
char *optLevelXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/optimizationLevel/text()",
actcfg);
XPathObject optLevelObj(run_xpath(xpathCtx, optLevelXpath));
Free(optLevelXpath);
xmlNodeSetPtr nodes = optLevelObj->nodesetval;
if (nodes) {
*optlevel = mcopystr((const char*)optLevelObj->nodesetval->nodeTab[0]->content);
}
}
{
char *optFlagsXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
actcfg);
XPathObject optFlagsObj(run_xpath(xpathCtx, optFlagsXpath));
Free(optFlagsXpath);
xmlNodeSetPtr nodes = optFlagsObj->nodesetval;
if (nodes) {
*optflags = mcopystr((const char*)optFlagsObj->nodesetval->nodeTab[0]->content);
}
}
{
char *linkerOptsXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/freeTextLinkerOptions/text()",
actcfg);
XPathObject linkerOptsObj(run_xpath(xpathCtx, linkerOptsXpath));
Free(linkerOptsXpath);
xmlNodeSetPtr nodes = linkerOptsObj->nodesetval;
if (nodes != NULL && nodes->nodeNr > 0) {
*linkerOptions = mcopystr((const char*)nodes->nodeTab[0]->content);
}
}
{
//SolarisSpecificLibraries
char *solspeclibXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
actcfg);
XPathObject solspeclibObj(run_xpath(xpathCtx, solspeclibXpath));
Free(solspeclibXpath);
xmlNodeSetPtr nodes = solspeclibObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (solspeclibs) {
// go to last element
struct string_list* last_elem = solspeclibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)solspeclibObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//Solaris8SpecificLibraries
char *sol8speclibXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
actcfg);
XPathObject sol8speclibObj(run_xpath(xpathCtx, sol8speclibXpath));
Free(sol8speclibXpath);
xmlNodeSetPtr nodes = sol8speclibObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (sol8speclibs) {
// go to last element
struct string_list* last_elem = sol8speclibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)sol8speclibObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//LinuxSpecificLibraries
char *linuxspeclibXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
actcfg);
XPathObject linuxspeclibObj(run_xpath(xpathCtx, linuxspeclibXpath));
Free(linuxspeclibXpath);
xmlNodeSetPtr nodes = linuxspeclibObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (linuxspeclibs) {
// go to last element
struct string_list* last_elem = linuxspeclibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)linuxspeclibObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//FreeBSDSpecificLibraries
char *freebsdspeclibXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
actcfg);
XPathObject freebsdspeclibObj(run_xpath(xpathCtx, freebsdspeclibXpath));
Free(freebsdspeclibXpath);
xmlNodeSetPtr nodes = freebsdspeclibObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (freebsdspeclibs) {
// go to last element
struct string_list* last_elem = freebsdspeclibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)freebsdspeclibObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//Win32SpecificLibraries
char *win32speclibXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
actcfg);
XPathObject win32speclibObj(run_xpath(xpathCtx, win32speclibXpath));
Free(win32speclibXpath);
xmlNodeSetPtr nodes = win32speclibObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (win32speclibs) {
// go to last element
struct string_list* last_elem = win32speclibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)win32speclibObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//TTCN3preprocessor
char *ttcn3preproc = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
actcfg);
XPathObject ttcn3preprocObj(run_xpath(xpathCtx, ttcn3preproc));
Free(ttcn3preproc);
xmlNodeSetPtr nodes = ttcn3preprocObj->nodesetval;
if (nodes) {
*ttcn3prep = mcopystr((const char*)ttcn3preprocObj->nodesetval->nodeTab[0]->content);
}
}
{
// additionalObjects
char *additionalObjectsXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
actcfg);
XPathObject additionalObjectsObj(run_xpath(xpathCtx, additionalObjectsXpath));
Free(additionalObjectsXpath);
xmlNodeSetPtr nodes = additionalObjectsObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add to the end of list
if (additionalObjects) {
// go to last element
struct string_list* last_elem = additionalObjects;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)additionalObjectsObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
}
}
}
{
//The project name needed the hierarchical projects
char* prjNameStr = 0;
char *prjNameStrXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()");
XPathObject prjName(run_xpath(xpathCtx, prjNameStrXpath));
if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
prjNameStr = (char*)prjName->nodesetval->nodeTab[0]->content;
}
Free(prjNameStrXpath);
append_to_library_list (prjNameStr, xpathCtx, actcfg);
//linkerLibraries
char *linkerlibsXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
actcfg);
XPathObject linkerlibsObj(run_xpath(xpathCtx, linkerlibsXpath));
Free(linkerlibsXpath);
xmlNodeSetPtr nodes = linkerlibsObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (linkerlibs) {
// go to last element
struct string_list* last_elem = linkerlibs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)linkerlibsObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
ProjectDescriptor* projDescr = projGenHelper.getTargetOfProject(*p_project_name);
if (projDescr) projDescr->addToLinkerLibs(last_elem->str);
}
}
}
{
//linkerLibrarySearchPath
char *linkerlibsearchXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
actcfg);
XPathObject linkerlibsearchObj(run_xpath(xpathCtx, linkerlibsearchXpath));
Free(linkerlibsearchXpath);
xmlNodeSetPtr nodes = linkerlibsearchObj->nodesetval;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
// add includes to the end of list
if (linkerlibsearchp) {
// go to last element
struct string_list* last_elem = linkerlibsearchp;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
char* content = (char*)linkerlibsearchObj->nodesetval->nodeTab[i]->content;
replacechar(&content);
last_elem->str = content;
ProjectDescriptor* projDescr = projGenHelper.getTargetOfProject(*p_project_name);
if (projDescr) projDescr->addToLibSearchPaths(last_elem->str);
}
}
}
if (generatorCommandOutput && local_argc != 0) { // only in case of top-level invocation
char* generatorCommandXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
actcfg);
XPathObject generatorCommandObj(run_xpath(xpathCtx, generatorCommandXpath));
Free(generatorCommandXpath);
if (generatorCommandObj->nodesetval && generatorCommandObj->nodesetval->nodeNr > 0) {
autostring generatorCommand;
generatorCommand = mcopystr((const char*)generatorCommandObj->nodesetval->nodeTab[0]->content);
// run the command and capture the output
printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand, (const char*)abs_tpd_name);
FILE* gc_fp = popen(generatorCommand, "r");
if (!gc_fp) {
ERROR("Could not execute command `%s'", (const char*)generatorCommand);
} else {
char buff[1024];
while (fgets(buff, sizeof(buff), gc_fp)!=NULL) {
*generatorCommandOutput = mputstr(*generatorCommandOutput, buff);
}
pclose(gc_fp);
}
}
}
if (target_placement_list && local_argc != 0) { // only in case of top-level invocation
char* targetPlacementXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
actcfg);
XPathObject targetPlacementObj(run_xpath(xpathCtx, targetPlacementXpath));
Free(targetPlacementXpath);
xmlNodeSetPtr nodes = targetPlacementObj->nodesetval;
const char* targetName = NULL;
const char* targetPlacement = NULL;
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
targetName = (const char*)nodes->nodeTab[i]->children->content;
}
else if (!strcmp((const char*)nodes->nodeTab[i]->name,"placement")) {
targetPlacement = (const char*)nodes->nodeTab[i]->children->content;
}
if (targetName && targetPlacement) { // collected both
if (target_placement_list) {
// go to last element
struct string2_list* last_elem = target_placement_list;
while (last_elem->next) last_elem = last_elem->next;
// add strings to last element if empty or create new last element and add it to that
if (last_elem->str1) {
last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
last_elem->str1 = mcopystr(targetName);
last_elem->str2 = mcopystr(targetPlacement);
}
targetName = targetPlacement = NULL; // forget both
}
}
}
{
// profiler file name
char* profilerXpath = mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/MakefileSettings/profiledFileList", actcfg);
XPathObject profiledFilesNameObj(run_xpath(xpathCtx, profilerXpath));
Free(profilerXpath);
xmlNodeSetPtr nodes = profiledFilesNameObj->nodesetval;
if (nodes && nodes->nodeNr > 0) {
const char *uri = 0, *path = 0, *raw = 0;
for (xmlAttrPtr attr = nodes->nodeTab[0]->properties; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "projectRelativePath")) {
path = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "relativeURI")) {
uri = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "rawURI")) {
raw = (const char*)attr->children->content;
}
else {
WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[0]->name);
}
} // next attribute
if (path == NULL) {
ERROR("A profiledFileList must have a projectRelativePath");
}
else {
if (uri == NULL && raw == NULL) {
ERROR("A profiledFileList must have either relativeURI or rawURI");
}
else {
cstring cpath(path);
if (files.has_key(cpath)) {
ERROR("profiledFileLists and FileResources must be unique!");
}
else {
// add the file to the end of the list
struct string_list* new_item = NULL;
if (*profiled_file_list == NULL) {
*profiled_file_list = (struct string_list*)Malloc(sizeof(struct string_list));
new_item = *profiled_file_list;
}
else {
new_item = *profiled_file_list;
while(new_item->next != NULL) {
new_item = new_item->next;
}
new_item->next = (struct string_list*)Malloc(sizeof(struct string_list));
new_item = new_item->next;
}
new_item->str = mcopystr(path);
new_item->next = NULL;
// add the file to the map of files to be copied to the working directory
char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
files.add(cpath, ruri);
}
}
}
}
}
} // If get_config_mode
// collect the required configurations
struct config_struct* config_elem = all_configs;
{
if (required_configs && get_config_mode) {
char* cfgConfigsXpath(mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration"));
XPathObject cfgConfigsObjects(run_xpath(xpathCtx, cfgConfigsXpath));
Free(cfgConfigsXpath);
xmlNodeSetPtr configs = cfgConfigsObjects->nodesetval;
if (configs) {
// Go through configurations
for (int i = 0; i < configs->nodeNr; ++i) {
xmlAttrPtr currentNode = configs->nodeTab[i]->properties;
const char* configName = NULL;
for (xmlAttrPtr attr = currentNode; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "name")) {
configName = (const char*)attr->children->content;
}
}
char* cfgReqsXpath(mprintf(
"/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
"/ProjectProperties/ConfigurationRequirements/configurationRequirement"
, configName));
while(config_elem->next != NULL) {
config_elem = config_elem->next;
}
config_elem->project_name = mcopystr(*p_project_name);
config_elem->project_conf = mcopystr(configName);
config_elem->is_active = strcmp(configName, actcfg) == 0;
struct config_struct* next_elem = (struct config_struct*)Malloc(sizeof(struct config_struct));
config_struct_init(next_elem);
config_elem->next = next_elem;
XPathObject reqcfgObjects(run_xpath(xpathCtx, cfgReqsXpath));
Free (cfgReqsXpath);
xmlNodeSetPtr reqConfigs = reqcfgObjects->nodesetval;
// Go through the required configurations of configurations
if (reqConfigs) for (int j = 0; j < reqConfigs->nodeNr; ++j) {
xmlNodePtr curNodePtr = reqConfigs->nodeTab[j]->children;
const char* projectName = NULL;
const char* reqConfig = NULL;
while(curNodePtr) {
if (!strcmp((const char*)curNodePtr->name, "projectName")) {
projectName = (const char*)curNodePtr->children->content;
}
if (!strcmp((const char*)curNodePtr->name, "rerquiredConfiguration") || // backward compatibility
!strcmp((const char*)curNodePtr->name, "requiredConfiguration")) {
reqConfig = (const char*)curNodePtr->children->content;
}
curNodePtr = curNodePtr->next;
}
// Check if the required configuration is already inserted.
struct string2_list* last_req = config_elem->requirements;
boolean already_in = FALSE;
while (last_req && last_req->str1 != NULL && last_req->str2 != NULL && already_in == FALSE) {
if (strcmp(last_req->str1, projectName) == 0 && strcmp(last_req->str2, reqConfig) == 0) {
already_in = TRUE;
break;
}
last_req = last_req->next;
}
// If not, insert into the requirements of the configuration
if (already_in == FALSE) {
last_req->str1 = mcopystr(projectName);
last_req->str2 = mcopystr(reqConfig);
struct string2_list* next_req = (struct string2_list*)Malloc(sizeof(struct string2_list));
next_req->str1 = NULL;
next_req->str2 = NULL;
next_req->next = NULL;
last_req->next = next_req;
last_req = next_req;
}
} // ReqConfigs
} // Configs
} // If configs
}
}
// Referenced projects
{
XPathObject subprojects(run_xpath(xpathCtx,
"/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject"));
xmlNodeSetPtr nodes = subprojects->nodesetval;
//Go through ReferencedProjects
if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
const char *name = NULL, *projectLocationURI = NULL;
char *tpdName_loc = NULL;
// FIXME: this assumes every ReferencedProject has name and URI.
// This is not necessarily so if the referenced project was closed
// when the project was exported to TPD.
// Luckily, the name from the closed project will be overwritten
// by the name from the next ReferencedProject. However, if some pervert
// changes the next ReferencedProject to have the projectLocationURI
// as the first attribute, it will be joined to the name
// of the previous, closed, ReferencedProject.
//Go through attributes
for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
if (!strcmp((const char*)attr->name, "name")) {
name = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name,"projectLocationURI")) {
projectLocationURI = (const char*)attr->children->content;
}
else if (!strcmp((const char*)attr->name, "tpdName")) {
//Allocate memory
tpdName_loc = mcopystr((char*)attr->children->content);
}
}
//We don't want to orerride an absolute location with -I, tpdName remains NULL
boolean not_abs_path = projectLocationURI &&
#if defined WIN32 && defined MINGW
/* On native Windows the absolute path name shall begin with
* a drive letter, colon and backslash */
(((projectLocationURI[0] < 'A' || projectLocationURI[0] > 'Z') &&
(projectLocationURI[0] < 'a' || projectLocationURI[0] > 'z')) ||
projectLocationURI[1] != ':' || projectLocationURI[2] != '\\');
#else
/* On UNIX-like systems the absolute path name shall begin with
* a slash */
projectLocationURI[0] != '/';
#endif
if (!tpdName_loc && not_abs_path) {
//Allocate memory: +5 because .tpd + closing 0
tpdName_loc = (char*)Malloc((strlen(name) + 5) * sizeof(char));
//Default name: name + .tpd
strcpy(tpdName_loc, name);
strcat(tpdName_loc, ".tpd");
}else if (!not_abs_path) {
Free(tpdName_loc);
tpdName_loc = NULL;
}
if (name && projectLocationURI) { // collected both
// see if there is a specified configuration for the project
ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
if (projDesc) projDesc->addToReferencedProjects(name);
const char *my_actcfg = NULL;
int my_argc = 0;
char *my_args[] = { NULL };
char **my_argv = my_args + 0;
boolean my_free_argv = FALSE;
int my_optind = 0;
boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down
my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, my_Zflag = *p_Zflag, my_Hflag = *p_Hflag,
my_sflag = 0, my_Lflag = 0, my_lflag = 0, my_mflag = 0,
my_quflag = 0, my_dsflag = 0, my_dbflag = 0, my_drflag = 0,
my_dtflag = 0, my_dxflag = 0, my_djflag = 0, my_doerflag = 0, my_fxflag = 0, my_doflag = 0,
my_gfflag = 0, my_lnflag = 0, my_isflag = 0, my_asflag = 0,
my_swflag = 0, my_Yflag = 0, my_Mflag = *p_Mflag, my_Eflag = 0, my_nflag = *p_nflag,
my_Nflag = 0,
my_diflag = *p_diflag,
my_duflag = 0;
boolean my_enable_legacy_encoding = 0;
boolean my_realtime_features = 0;
boolean my_oop_features = 0;
boolean my_charstring_compat = 0;
char *my_ets = NULL;
char *my_proj_name = NULL;
char *my_csmode = *p_csmode;
autostring abs_projectLocationURI;
if (not_abs_path) {
abs_projectLocationURI = compose_path_name(abs_tpd_dir, projectLocationURI);
} else {
//If absolute directory, then just copy the URI
abs_projectLocationURI = mcopystr(projectLocationURI);
}
char* sub_proj_abs_work_dir = NULL;
//Insert children of the project
if (get_config_mode && config_elem->project_name != NULL) {
struct config_struct* tmp = all_configs;
boolean already_in = FALSE;
while (tmp && tmp->project_name != NULL && already_in == FALSE) {
if (strcmp(tmp->project_name, config_elem->project_name) == 0) {
struct string_list* last_child = tmp->children;
while(last_child && last_child->str != NULL) {
if (strcmp(last_child->str, name) == 0) {
already_in = TRUE;
break;
}
last_child = last_child->next;
}
if (already_in == FALSE) {
last_child->str = mcopystr(name);
struct string_list* next_child = (struct string_list*)Malloc(sizeof(string_list));
next_child->str = NULL;
next_child->next = NULL;
last_child->next = next_child;
last_child = next_child;
//break; needed???
}
}
tmp = tmp->next;
}
}
const char* abs_projectLocationURIchar = abs_projectLocationURI.extract();
tpd_result success = process_tpd_internal(&abs_projectLocationURIchar, tpdName_loc,
my_actcfg, file_list_path, &my_argc, &my_argv, &my_free_argv, &my_optind, &my_ets, &my_proj_name,
&my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag,
&my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir,
sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines,
prep_includes, prep_defines, prep_undefines, &my_csmode,
&my_quflag, &my_dsflag, cxxcompiler, optlevel, optflags, linkerOptions, semantic_check_only, disable_attibute_validation,
&my_dbflag, &my_drflag, &my_dtflag, &my_dxflag, &my_djflag, &my_doerflag, &my_fxflag, &my_doflag,
&my_gfflag, &my_lnflag, &my_isflag, &my_asflag, &my_swflag, &my_Yflag, &my_Mflag, &my_Eflag, &my_nflag, &my_Nflag, &my_diflag,
&my_enable_legacy_encoding, &my_duflag, &my_realtime_features, &my_oop_features, &my_charstring_compat,
solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs,
ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, &my_Zflag,
&my_Hflag, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files, required_configs, profiled_file_list,
search_paths, n_search_paths, makefileScript, all_configs);
autostring sub_proj_abs_work_dir_as(sub_proj_abs_work_dir); // ?!
abs_projectLocationURI = abs_projectLocationURIchar;
if (get_config_mode) {
if (!projGenHelper.insertAndCheckProjectName((const char*)abs_projectLocationURI, name)) {
ERROR("In project `%s', the referenced project `%s's name attribute should be the same as the referenced project's name.",
*p_tpd_name, (const char*)abs_projectLocationURI);
}
}
if (success == TPD_SUCCESS && !get_config_mode) {
my_actcfg = get_act_config(required_configs, my_proj_name);
if (recursive) { // call ttcn3_makefilegen on referenced project's tpd file
// -r is not needed any more because top level process traverses all projects recursively
expstring_t command = mprintf("%s -cVD", program_name);
if (force_overwrite) command = mputc(command, 'f');
if (prefix_workdir) command = mputc(command, 'W');
if (*p_gflag) command = mputc(command, 'g');
if (*p_sflag) command = mputc(command, 's');
if (*p_aflag) command = mputc(command, 'a');
if (*p_Rflag) command = mputc(command, 'R');
if (*p_lflag) command = mputc(command, 'l');
if (*p_mflag) command = mputc(command, 'm');
if (*p_Zflag) command = mputc(command, 'Z');
if (*p_Hflag) command = mputc(command, 'H');
command = mputstr(command, " -t ");
command = mputstr(command, (const char*)abs_projectLocationURI);
if (my_actcfg) {
command = mputstr(command, " -b ");
command = mputstr(command, my_actcfg);
}
autostring sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI));
const char * sub_proj_effective_work_dir = sub_proj_abs_work_dir ? sub_proj_abs_work_dir : (const char*)sub_tpd_dir;
if (!gen_only_top_level) {
if (run_command_list) {
// go to last element
struct string2_list* last_elem = run_command_list;
while (last_elem->next) last_elem = last_elem->next;
// add strings to last element if empty or create new last element and add it to that
if (last_elem->str1 || last_elem->str2) {
last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
last_elem->str1 = mcopystr(sub_proj_effective_work_dir);
last_elem->str2 = command;
} else {
ERROR("Internal error: cannot add command to list");
}
} else {
Free(command);
}
// add working dir to the end of list
if (sub_project_dirs) {
// go to last element
struct string_list* last_elem = sub_project_dirs;
while (last_elem->next) last_elem = last_elem->next;
// add string to last element if empty or create new last element and add it to that
if (last_elem->str) {
last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
autostring cwd_as(get_working_dir());
last_elem->str = (*p_aflag) ? mcopystr(sub_proj_effective_work_dir) : get_relative_dir(sub_proj_effective_work_dir, (const char*)cwd_as);
}
}
for (int z = 0; z < my_argc; ++z) {
if (*p_cflag) {
// central storage, keep in separate container
base_files.add(my_argv[z]); // string was allocated with new
}
else {
const cstring tmp(my_argv[z]);
if (!files.has_key(tmp)){
files.add(tmp, my_argv[z]);
} else if (my_free_argv) {
Free(my_argv[z]);
}
}
}
if (my_free_argv) {
Free(my_argv); // free the array; we keep the pointers
}
Free(my_ets);
}
else {
if (my_free_argv) {
for (int z = 0; z < my_argc; ++z) {
Free(my_argv[z]);
}
Free(my_argv);
}
if (success == TPD_FAILED) {
ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
result = TPD_FAILED;
}
// else TPD_SKIPPED, keep quiet
}
Free(my_proj_name);
Free(tpdName_loc);
name = projectLocationURI = tpdName_loc = NULL; // forget all
}
} // next referenced project
}
if (output_file) {
if (get_path_status(output_file) == PS_DIRECTORY) {
// points to existing dir; use as-is
}
else { // we assume it points to a file: not our problem
output_file = NULL;
}
}
// (argc - optind) is the number of non-option arguments (assumed to be files)
// given on the command line.
size_t new_argc = local_argc - local_optind + files.size() + base_files.size();
char ** new_argv = (char**)Malloc(sizeof(char*) * new_argc);
size_t n = 0;
// First, copy the filenames gathered from the TPD
//
// We symlink the files into the working directory
// and pass only the filename to the makefile generator
for (size_t nf = files.size(); n < nf; ++n) {
const char *fn = files.get_nth_elem(n); // relativeURI to the TPD location
autostring dir_n (get_dir_from_path (fn));
autostring file_n(get_file_from_path(fn));
autostring rel_n (get_absolute_dir(dir_n, abs_tpd_dir, TRUE));
autostring abs_n (compose_path_name(rel_n, file_n));
if (local_argc == 0) {
// We are being invoked recursively, for a referenced TPD.
// Do not symlink; just return absolute paths to the files.
if (*fn == '/') {
if (*p_cflag) {
// compose with workdir
new_argv[n] = compose_path_name(abs_workdir, file_n);
} else {
// it's an absolute path, copy verbatim
new_argv[n] = mcopystr(fn); // fn will be destroyed, pass a copy
}
}
else { // relative path
if (*p_cflag) {
// compose with workdir
new_argv[n] = compose_path_name(abs_workdir, file_n);
// Do not call file_n.extract() : the composed path will be returned,
// its component will need to be deallocated here.
}
else {
// compose with tpd dir
new_argv[n] = const_cast<char*>(abs_n.extract());
}
}
}
else { // we are processing the top-level TPD
#ifndef MINGW
if (!*p_Pflag) {
int fd = open(abs_n, O_RDONLY);
if (fd >= 0) { // successfully opened
close(fd);
if (output_file) {
file_n = compose_path_name(output_file, file_n);
}
//TODO ! compose with output_file
// save into list: add symlink data to the end of list
if (create_symlink_list) {
// go to last element
struct string2_list* last_elem = create_symlink_list;
while (last_elem->next) last_elem = last_elem->next;
// add strings to last element if empty or create new last element and add it to that
if (last_elem->str1) {
last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
last_elem = last_elem->next;
last_elem->next = NULL;
}
last_elem->str1 = mcopystr(abs_n);
last_elem->str2 = mcopystr(file_n);
}
}
else {
ERROR("%s does not exist", (const char*)abs_n);
}
}
#endif
if (*p_Pflag) {
if (*p_aflag) {
puts((const char *)abs_n);
} else {
autostring dir_part(get_dir_from_path(abs_n));
autostring file_part(get_file_from_path(abs_n));
autostring rel_dir_part(get_relative_dir((const char *)dir_part, file_list_path ? file_list_path : (const char *)abs_tpd_dir));
autostring rel_dir_file_part(compose_path_name((const char *)rel_dir_part, (const char *)file_part));
puts((const char *)rel_dir_file_part);
}
}
new_argv[n] = const_cast<char *>(file_n.extract());
}
}
// Print the TPD too.
if (*p_Pflag) {
if (*p_aflag) {
puts((const char *)abs_tpd_name);
} else {
autostring dir_part(get_dir_from_path(*p_tpd_name));
autostring file_part(get_file_from_path(*p_tpd_name));
autostring rel_dir_part(get_relative_dir(dir_part, file_list_path ? file_list_path : abs_tpd_dir));
autostring rel_dir_file_part(compose_path_name(rel_dir_part, file_part));
const char *rel_tpd_name = (const char *)rel_dir_file_part;
puts(rel_tpd_name);
}
}
// base_files from referenced projects
for (size_t bf = 0, bs = base_files.size(); bf < bs; ++bf, ++n) {
new_argv[n] = base_files[bf];
}
base_files.clear(); // string ownership transfered
// Then, copy the filenames from the command line.
for (int a = *p_optind; a < *p_argc; ++a, ++n) {
// String may be from main's argv; copy to the heap.
new_argv[n] = mcopystr((*p_argv)[a]);
}
if (local_argc > 0) { // it is the outermost call
clear_seen_tpd_files(seen_tpd_files);
}
// replace argv only if not config mode
if (!get_config_mode) {
if (*p_free_argv) {
for (int i = 0; i < *p_argc; ++i) {
Free((*p_argv)[i]);
}
Free(*p_argv);
}
else {
*p_free_argv = TRUE;
}
*p_argv = new_argv;
*p_argc = new_argc;
*p_optind = 0;
} else {
for (size_t i = 0; i < new_argc; ++i) {
Free(new_argv[i]);
}
Free(new_argv);
}
// finally...
for (size_t i = 0, e = files.size(); i < e; ++i) {
Free(const_cast<char*>(files.get_nth_elem(i)));
}
files.clear();
for (size_t i = 0, e = folders.size(); i < e; ++i) {
Free(const_cast<char*>(folders.get_nth_elem(i)));
}
folders.clear();
excluded_files.clear();
excluded_folders.clear();
path_vars.clear();
xmlCleanupParser();
// ifdef debug
xmlMemoryDump();
return result;
}