/****************************************************************************** * 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; }