1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
23 ******************************************************************************/
32 #include <sys/types.h>
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include <libxml/xpath.h>
40 #define LIBXML_SCHEMAS_ENABLED
41 #include <libxml/xmlschemastypes.h>
43 #include "../common/memory.h"
45 // Do _NOT_ #include "string.hh", it drags in ustring.o, common/Quadruple.o,
46 // Int.o, ttcn3/PatternString.o, and then the entire AST :(
48 #include "ProjectGenHelper.hh"
49 #include "../common/path.h"
50 #include "ttcn3/ttcn3_preparser.h"
51 #include "asn1/asn1_preparser.h"
54 void ERROR (const char *fmt
, ...);
55 void WARNING(const char *fmt
, ...);
56 void NOTIFY (const char *fmt
, ...);
57 void DEBUG (const char *fmt
, ...);
60 void fatal_error(const char * filename
, int lineno
, const char * fmt
, ...)
61 __attribute__ ((__format__ (__printf__
, 3, 4), __noreturn__
));
63 void fatal_error(const char * filename
, int lineno
, const char * fmt
, ...)
65 fputs(filename
, stderr
);
66 fprintf(stderr
, ":%d: ", lineno
);
69 vfprintf(stderr
, fmt
, va
);
74 ProjectGenHelper
& projGenHelper
= ProjectGenHelper::Instance();
76 /// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
77 xmlXPathObjectPtr
run_xpath(xmlXPathContextPtr xpathCtx
, const char *xpathExpr
)
79 xmlXPathObjectPtr xpathObj
= xmlXPathEvalExpression(
80 (const xmlChar
*)xpathExpr
, xpathCtx
);
81 if(xpathObj
== NULL
) {
82 fprintf(stderr
,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr
);
93 explicit XmlDoc(xmlDocPtr p
) : doc_(p
) {}
95 if (doc_
!= NULL
) xmlFreeDoc(doc_
);
97 operator xmlDocPtr() const { return doc_
; }
104 explicit XPathContext(xmlXPathContextPtr c
) : ctx_(c
) {}
106 if (ctx_
!= NULL
) xmlXPathFreeContext(ctx_
);
108 operator xmlXPathContextPtr() const { return ctx_
; }
110 xmlXPathContextPtr ctx_
;
115 explicit XPathObject(xmlXPathObjectPtr o
) : xpo_(o
) {}
117 if (xpo_
!= NULL
) xmlXPathFreeObject(xpo_
);
119 operator xmlXPathObjectPtr() const { return xpo_
; }
120 xmlXPathObjectPtr
operator->() const { return xpo_
; }
122 xmlXPathObjectPtr xpo_
;
125 //------------------------------------------------------------------
126 /// compare-by-content wrapper of a plain C string
128 explicit cstring(const char *s
) : str(s
) {}
129 void destroy() const;
130 operator const char*() const { return str
; }
133 friend boolean
operator<(const cstring
& l
, const cstring
& r
);
134 friend boolean
operator==(const cstring
& l
, const cstring
& r
);
137 void cstring::destroy() const {
138 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
141 boolean
operator<(const cstring
& l
, const cstring
& r
) {
142 return strcmp(l
.str
, r
.str
) < 0;
145 boolean
operator==(const cstring
& l
, const cstring
& r
) {
146 return strcmp(l
.str
, r
.str
) == 0;
149 /// RAII for C string
150 struct autostring
: public cstring
{
151 /// Constructor; takes over ownership
152 explicit autostring(const char *s
= 0) : cstring(s
) {}
154 // He who can destroy a thing, controls that thing -- Paul Muad'Dib
155 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
157 /// %Assignment; takes over ownership
158 const autostring
& operator=(const char *s
) {
159 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
163 /// Relinquish ownership
164 const char *extract() {
165 const char *retval
= str
;
170 autostring(const autostring
&);
171 autostring
& operator=(const autostring
&);
175 bool validate_tpd(const XmlDoc
& xml_doc
, const char* tpd_file_name
, const char* xsd_file_name
)
177 xmlLineNumbersDefault(1);
179 xmlSchemaParserCtxtPtr ctxt
= xmlSchemaNewParserCtxt(xsd_file_name
);
181 ERROR("Unable to create xsd context for xsd file `%s'", xsd_file_name
);
184 xmlSchemaSetParserErrors(ctxt
, (xmlSchemaValidityErrorFunc
)fprintf
, (xmlSchemaValidityWarningFunc
)fprintf
, stderr
);
186 xmlSchemaPtr schema
= xmlSchemaParse(ctxt
);
188 ERROR("Unable to parse xsd file `%s'", xsd_file_name
);
189 xmlSchemaFreeParserCtxt(ctxt
);
193 xmlSchemaValidCtxtPtr xsd
= xmlSchemaNewValidCtxt(schema
);
195 ERROR("Schema validation error for xsd file `%s'", xsd_file_name
);
196 xmlSchemaFree(schema
);
197 xmlSchemaFreeParserCtxt(ctxt
);
200 xmlSchemaSetValidErrors(xsd
, (xmlSchemaValidityErrorFunc
) fprintf
, (xmlSchemaValidityWarningFunc
) fprintf
, stderr
);
202 int ret
= xmlSchemaValidateDoc(xsd
, xml_doc
);
204 xmlSchemaFreeValidCtxt(xsd
);
205 xmlSchemaFree(schema
);
206 xmlSchemaFreeParserCtxt(ctxt
);
207 xmlSchemaCleanupTypes();
210 return true; // successful validation
212 ERROR("TPD file `%s' is invalid according to schema `%s'", tpd_file_name
, xsd_file_name
);
215 ERROR("TPD validation of `%s' generated an internal error in libxml2", tpd_file_name
);
220 /** Extract a boolean value from the XML, if it exists otherwise flag is unchanged
222 * @param xpathCtx XPath context object
223 * @param actcfg name of the active configuration
224 * @param option name of the value
225 * @param flag pointer to the variable to receive the value
227 void xsdbool2boolean(const XPathContext
& xpathCtx
, const char *actcfg
,
228 const char *option
, boolean
* flag
)
230 char *xpath
= mprintf(
231 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
232 "/ProjectProperties/MakefileSettings/%s[text()='true']",
234 XPathObject
xpathObj(run_xpath(xpathCtx
, xpath
));
237 if (xpathObj
->nodesetval
&& xpathObj
->nodesetval
->nodeNr
> 0) {
242 extern "C" string_list
* getExternalLibs(const char* projName
)
244 if (!projGenHelper
.getZflag()) return NULL
;
245 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
246 if (!proj
) return NULL
;
248 std::vector
<const char*> externalLibs
;
249 projGenHelper
.getExternalLibs(externalLibs
);
251 if (0 == externalLibs
.size()) return NULL
;
253 struct string_list
* head
= (struct string_list
*)Malloc(sizeof(struct string_list
));
254 struct string_list
* last_elem
= head
;
255 struct string_list
* tail
= head
;
257 for (size_t i
= 0; i
< externalLibs
.size(); ++i
) {
259 last_elem
->str
= mcopystr(externalLibs
[i
]);
260 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
261 last_elem
= last_elem
->next
;
268 extern "C" string_list
* getExternalLibPaths(const char* projName
)
270 if (!projGenHelper
.getZflag()) return NULL
;
271 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
272 if (!proj
) return NULL
;
274 std::vector
<const char*> externalLibs
;
275 projGenHelper
.getExternalLibSearchPaths(externalLibs
);
277 if (0 == externalLibs
.size()) return NULL
;
279 struct string_list
* head
= (struct string_list
*)Malloc(sizeof(struct string_list
));
280 struct string_list
* last_elem
= head
;
281 struct string_list
* tail
= head
;
283 for (size_t i
= 0; i
< externalLibs
.size(); ++i
) {
285 last_elem
->str
= mcopystr(externalLibs
[i
]);
286 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
287 last_elem
= last_elem
->next
;
294 extern "C" string_list
* getRefWorkingDirs(const char* projName
)
296 if (!projGenHelper
.getZflag()) return NULL
;
297 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
298 if (!proj
) FATAL_ERROR("Project \"%s\" was not found in the project list", projName
);
300 struct string_list
* head
= (struct string_list
*)Malloc(sizeof(struct string_list
));
301 struct string_list
* last_elem
= head
;
302 struct string_list
* tail
= head
;
303 last_elem
->str
= NULL
;
304 last_elem
->next
= NULL
;
305 for (size_t i
= 0; i
< proj
->numOfRefProjWorkingDirs(); ++i
) {
307 last_elem
->str
= mcopystr(proj
->getRefProjWorkingDir(i
).c_str());
308 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
309 last_elem
= last_elem
->next
;
316 extern "C" string2_list
* getLinkerLibs(const char* projName
)
319 if (!projGenHelper
.getZflag()) return NULL
;
320 if (1 == projGenHelper
.numOfProjects() || 0 == projGenHelper
.numOfLibs()){
321 return NULL
; //no library
323 ProjectDescriptor
* projLib
= projGenHelper
.getTargetOfProject(projName
);
324 if (!projLib
) FATAL_ERROR("Project \"%s\" was not found in the project list", projName
);
326 struct string2_list
* head
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
327 struct string2_list
* last_elem
= head
;
328 struct string2_list
* tail
= head
;
329 last_elem
->next
= NULL
;
330 last_elem
->str1
= NULL
;
331 last_elem
->str2
= NULL
;
332 for (std::map
<std::string
, ProjectDescriptor
>::const_iterator it
= projGenHelper
.getHead();
333 it
!= projGenHelper
.getEnd(); ++it
) {
334 if ((it
->second
).isLibrary()) {
335 if (!(it
->second
).getLinkingStrategy() &&
336 !projLib
->hasLinkerLibTo((it
->second
).getProjectName())) { // static linked library
339 std::string relPath
= projLib
->setRelativePathTo((it
->second
).getProjectAbsWorkingDir());
340 if (relPath
== std::string(".")) {
341 continue; // the relpath shows to itself
344 last_elem
->str1
= mcopystr(relPath
.c_str());
345 last_elem
->str2
= mcopystr((it
->second
).getTargetExecName().c_str());
346 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
347 last_elem
= last_elem
->next
;
353 if (head
->str1
&& head
->str2
)
359 extern "C" const char* getLibFromProject(const char* projName
)
361 if (!projGenHelper
.getZflag()) return NULL
;
362 ProjectDescriptor
* lib
= projGenHelper
.getTargetOfProject(projName
);
363 if (lib
) return lib
->getTargetExecName().c_str();
367 extern "C" void erase_libs() {
368 projGenHelper
.cleanUp();
371 extern "C" void print_libs() {
372 projGenHelper
.print();
376 extern "C" boolean
hasSubProject(const char* projName
) {
377 if (!projGenHelper
.getZflag()) return FALSE
;
378 if (projGenHelper
.getHflag())
379 return static_cast<boolean
>(projGenHelper
.hasReferencedProject());
380 else if(std::string(projName
) == projGenHelper
.getToplevelProjectName())
381 return static_cast<boolean
>(projGenHelper
.hasReferencedProject());
386 extern "C" boolean
hasExternalLibrary(const char* libName
, const char* projName
) {
387 if (!projGenHelper
.getZflag()) return FALSE
;
388 ProjectDescriptor
* projLib
= projGenHelper
.getTargetOfProject(projName
);
389 if (projLib
&& projLib
->hasLinkerLib(libName
))
395 extern "C" boolean
isTopLevelExecutable(const char* projName
) {
396 if (!projGenHelper
.getZflag()) return false;
397 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
398 if (projGenHelper
.getToplevelProjectName() != std::string(projName
)) return FALSE
;
399 if (proj
&& proj
->isLibrary())
405 extern "C" boolean
isDynamicLibrary(const char* key
) {
406 if (!projGenHelper
.getZflag()) return false;
407 ProjectDescriptor
* proj
= projGenHelper
.getProjectDescriptor(key
);
408 if (proj
) return proj
->getLinkingStrategy();
409 FATAL_ERROR("Library \"%s\" was not found", key
);
413 extern "C" const char* getTPDFileName(const char* projName
) {
414 if (!projGenHelper
.getZflag()) return NULL
;
415 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
416 if (proj
) return proj
->getTPDFileName().c_str();
417 FATAL_ERROR("TPD file name to project \"%s\" was not found", projName
);
420 extern "C" const char* getPathToRootDir(const char* projName
) {
421 if (!projGenHelper
.getZflag()) return NULL
;
422 ProjectDescriptor
* proj
= projGenHelper
.getTargetOfProject(projName
);
423 const char* rootDir
= projGenHelper
.getRootDirOS(projName
).c_str();
424 if (proj
&& rootDir
) {
427 FATAL_ERROR("Project \"%s\": no relative path was found to top directory at OS level.", projName
);
430 extern "C" const char* findLibraryPath(const char* libraryName
, const char* projName
)
432 if (!projGenHelper
.getZflag()) return NULL
;
433 ProjectDescriptor
* projLib
= projGenHelper
.getTargetOfProject(projName
);
434 if (!projLib
) FATAL_ERROR("Project \"%s\" was not found in the project list", projName
);
435 ProjectDescriptor
* libLib
= projGenHelper
.getProjectDescriptor(libraryName
);
436 if (!libLib
) return NULL
;
437 std::string str
= projLib
->setRelativePathTo(libLib
->getProjectAbsWorkingDir());
438 size_t refIndex
= projLib
->getLibSearchPathIndex(libLib
->getProjectName());
439 if (refIndex
> projLib
->numOfLibSearchPaths()) return NULL
;
440 projLib
->setLibSearchPath(refIndex
, str
);
441 return projLib
->getLibSearchPath(libLib
->getProjectName());
444 extern "C" const char* findLibraryName(const char* libraryName
, const char* projName
)
446 if (!projGenHelper
.getZflag()) return NULL
;
447 ProjectDescriptor
* projLib
= projGenHelper
.getTargetOfProject(projName
);
448 if (!projLib
) FATAL_ERROR("Project \"%s\" was not found in the project list", projName
);
449 ProjectDescriptor
* libLib
= projGenHelper
.getProjectDescriptor(libraryName
);
450 if (!libLib
) return NULL
;
451 for (size_t i
= 0; i
< projLib
->numOfReferencedProjects(); ++i
) {
452 const std:: string refProjName
= projLib
->getReferencedProject(i
);
453 ProjectDescriptor
* refLib
= projGenHelper
.getTargetOfProject(refProjName
.c_str());
454 if (refLib
->getTargetExecName() == std::string(libraryName
))
460 extern "C" boolean
isTtcn3ModuleInLibrary(const char* moduleName
)
462 if (!projGenHelper
.getZflag()) return FALSE
;
463 return (boolean
)projGenHelper
.isTtcn3ModuleInLibrary(moduleName
);
466 extern "C" boolean
isAsn1ModuleInLibrary(const char* moduleName
)
468 if (!projGenHelper
.getZflag()) return FALSE
;
469 return (boolean
)projGenHelper
.isAsn1ModuleInLibrary(moduleName
);
472 extern "C" boolean
isSourceFileInLibrary(const char* fileName
)
474 if (!projGenHelper
.getZflag()) return FALSE
;
475 return (boolean
)projGenHelper
.isSourceFileInLibrary(fileName
);
478 extern "C" boolean
isHeaderFileInLibrary(const char* fileName
)
480 if (!projGenHelper
.getZflag()) return FALSE
;
481 return (boolean
)projGenHelper
.isHeaderFileInLibrary(fileName
);
484 extern "C" boolean
isTtcnPPFileInLibrary(const char* fileName
)
486 if (!projGenHelper
.getZflag()) return FALSE
;
487 return (boolean
)projGenHelper
.isTtcnPPFileInLibrary(fileName
);
491 extern "C" boolean
buildObjects(const char* projName
, boolean add_referenced
)
493 if (!projGenHelper
.getZflag()) return FALSE
;
494 if (projGenHelper
.getHflag()) return FALSE
;
495 if (add_referenced
) return FALSE
;
496 ProjectDescriptor
* desc
=projGenHelper
.getTargetOfProject(projName
);
497 if (desc
&& desc
->isLibrary()) return FALSE
;
501 void append_to_library_list (const char* prjName
,
502 const XPathContext
& xpathCtx
,
505 if (!projGenHelper
.getZflag()) return;
507 char *exeXpath
= mprintf(
508 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
509 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
511 XPathObject
exeObj(run_xpath(xpathCtx
, exeXpath
));
513 std::string lib_name
;
514 if (exeObj
->nodesetval
&& exeObj
->nodesetval
->nodeNr
> 0) {
515 const char* target_executable
= (const char*)exeObj
->nodesetval
->nodeTab
[0]->content
;
516 autostring
target_exe_dir(get_dir_from_path(target_executable
));
517 autostring
target_exe_file(get_file_from_path(target_executable
));
518 lib_name
= target_exe_file
;
519 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(prjName
);
521 projDesc
->setTargetExecName(lib_name
.c_str());
526 // data structures and functions to manage excluded folders/files
528 map
<cstring
, const char> excluded_files
;
530 boolean
is_excluded_file(const cstring
& path
, const char* project
) {
531 if (!excluded_files
.has_key(path
)) return false;
532 const char* proj
= excluded_files
[path
];
533 if (0 == strcmp(project
, proj
)) return true;
537 vector
<const char> excluded_folders
;
539 // Unfortunately, when "docs" is excluded, we need to drop
540 // files in "docs/", "docs/pdf/", "docs/txt/", "docs/txt/old/" etc;
541 // so it's not as simple as using a map :(
543 /** Checks whether a file is under an excluded folder
545 * @param path (relative) path of the file
546 * @return true if file is excluded, false otherwise
548 boolean
is_excluded_folder(const char *path
) {
549 boolean answer
= FALSE
;
550 size_t pathlen
= strlen(path
);
552 for (size_t i
= 0, end
= excluded_folders
.size(); i
< end
; ++i
) {
553 const char *xdir
= excluded_folders
[i
];
554 size_t xdlen
= strlen(xdir
);
555 if (pathlen
> xdlen
&& path
[xdlen
] == '/') {
556 // we may have a winner
557 if ((answer
= !strncmp(path
, xdir
, xdlen
))) break;
563 // How do you treat a raw info? You cook it, of course!
564 // Returns a newly allocated string.
565 char *cook(const char *raw
, const map
<cstring
, const char>& path_vars
)
567 const char *slash
= strchr(raw
, '/');
568 if (!slash
) { // Pretend that the slash is at the end of the string.
569 slash
= raw
+ strlen(raw
);
572 // Assume that a path variable reference is the first (or only) component
573 // of the path: ROOT in "ROOT/etc/issue".
574 autostring
prefix(mcopystrn(raw
, slash
- raw
));
575 if (path_vars
.has_key(prefix
)) {
576 char *cooked
= mcopystr(path_vars
[prefix
]);
577 bool ends_with_slash
= cooked
[strlen(cooked
)-1] == '/';
578 if (ends_with_slash
&& *slash
== '/') {
579 // Avoid paths with two slashes at the start; Cygwin thinks it's UNC
582 // If there was no '/' (only the path variable reference e.g "ROOT")
583 // then slash points to a null byte and the mputstr is a no-op.
584 cooked
= mputstr(cooked
, slash
);
588 // If the path variable could not be substituted,
589 // return (a copy of) the original.
590 return mcopystr(raw
);
593 void replacechar(char** content
) {
595 std::string s
= *content
;
597 while ((found
= s
.find('['))!= std::string::npos
){
598 s
.replace(found
,1, "${");
600 while ((found
= s
.find(']')) != std::string::npos
){
601 s
.replace(found
,1, "}");
603 *content
= mcopystr(s
.c_str());
606 static void clear_seen_tpd_files(map
<cstring
, int>& seen_tpd_files
) {
607 for (size_t i
= 0, num
= seen_tpd_files
.size(); i
< num
; ++i
) {
608 const cstring
& key
= seen_tpd_files
.get_nth_key(i
);
609 int *elem
= seen_tpd_files
.get_nth_elem(i
);
613 seen_tpd_files
.clear();
616 const char* get_act_config(struct string2_list
* cfg
, const char* project_name
) {
617 while (cfg
&& cfg
->str1
&& project_name
) {
618 if (!strcmp(cfg
->str1
, project_name
)) return cfg
->str2
;
624 static tpd_result
process_tpd_internal(const char *p_tpd_name
, char* tpdName
, const char *actcfg
,
625 const char *file_list_path
, int *p_argc
, char ***p_argv
,
626 int *p_optind
, char **p_ets_name
, char **p_project_name
,
627 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
628 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
629 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
630 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
631 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
632 struct string_list
* ttcn3_prep_defines
, struct string_list
* ttcn3_prep_undefines
, struct string_list
* prep_includes
,
633 struct string_list
* prep_defines
, struct string_list
* prep_undefines
, boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
,
634 char** cxxcompiler
, char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
,
635 boolean
* p_djflag
, boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
636 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, boolean
* p_Mflag
, boolean
*p_Eflag
, boolean
* p_nflag
,
637 boolean
* p_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
638 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
639 struct string_list
* linkerlibs
, struct string_list
* additionalObjects
, struct string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
,
640 boolean
*p_Zflag
, boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
641 struct string2_list
* run_command_list
, map
<cstring
, int>& seen_tpd_files
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
642 const char **search_paths
, size_t n_search_paths
);
644 extern "C" tpd_result
process_tpd(const char *p_tpd_name
, const char *actcfg
,
645 const char *file_list_path
, int *p_argc
, char ***p_argv
,
646 int *p_optind
, char **p_ets_name
, char **p_project_name
,
647 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
648 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
649 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
650 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
651 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
652 struct string_list
* ttcn3_prep_defines
, struct string_list
* ttcn3_prep_undefines
, struct string_list
* prep_includes
,
653 struct string_list
* prep_defines
, struct string_list
* prep_undefines
, boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
,
654 char** cxxcompiler
, char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
,
655 boolean
* p_djflag
, boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
656 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, boolean
* p_Mflag
, boolean
* p_Eflag
, boolean
* p_nflag
,
657 boolean
* p_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
658 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
659 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
, boolean
*p_Zflag
,
660 boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
661 struct string2_list
* run_command_list
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
662 const char **search_paths
, size_t n_search_paths
) {
664 map
<cstring
, int> seen_tpd_files
;
665 char *tpdName
= NULL
;
666 projGenHelper
.setZflag(*p_Zflag
);
667 projGenHelper
.setWflag(prefix_workdir
);
668 projGenHelper
.setHflag(*p_Hflag
);
669 tpd_result success
= process_tpd_internal(p_tpd_name
, tpdName
,
670 actcfg
, file_list_path
, p_argc
, p_argv
, p_optind
, p_ets_name
, p_project_name
,
671 p_gflag
, p_sflag
, p_cflag
, p_aflag
, preprocess
,
672 p_Rflag
, p_lflag
, p_mflag
, p_Pflag
,
673 p_Lflag
, recursive
, force_overwrite
, gen_only_top_level
,
674 output_file
, abs_work_dir_p
, sub_project_dirs
,
675 program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
,
676 ttcn3_prep_defines
, ttcn3_prep_undefines
, prep_includes
, prep_defines
,
677 prep_undefines
, p_csflag
, p_quflag
, p_dsflag
, cxxcompiler
,
678 optlevel
, optflags
, p_dbflag
, p_drflag
, p_dtflag
, p_dxflag
, p_djflag
,
679 p_fxflag
, p_doflag
, p_gfflag
, p_lnflag
, p_isflag
,
680 p_asflag
, p_swflag
, p_Yflag
, p_Mflag
, p_Eflag
, p_nflag
, p_diflag
, solspeclibs
, sol8speclibs
,
681 linuxspeclibs
, freebsdspeclibs
, win32speclibs
, ttcn3prep
,
682 linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, Dflag
, p_Zflag
,
683 p_Hflag
, generatorCommandOutput
, target_placement_list
, prefix_workdir
,
684 run_command_list
, seen_tpd_files
, required_configs
, profiled_file_list
,
685 search_paths
, n_search_paths
);
687 if (TPD_FAILED
== success
) exit(EXIT_FAILURE
);
689 if (false == projGenHelper
.sanityCheck()) {
690 fprintf (stderr
, "makefilegen exits\n");
694 projGenHelper
.generateRefProjectWorkingDirsTo(*p_project_name
);
696 for (size_t i
= 0, num
= seen_tpd_files
.size(); i
< num
; ++i
) {
697 const cstring
& key
= seen_tpd_files
.get_nth_key(i
);
698 int *elem
= seen_tpd_files
.get_nth_elem(i
);
702 seen_tpd_files
.clear();
707 // optind is the index of the next element of argv to be processed.
708 // Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
709 // seen already, or TPD_FAILED.
711 // Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
712 // (argv[], ets_name, other_files[], output_file) are allocated on the heap
713 // and need to be freed. On input, these strings point into argv.
714 // process_tpd() may alter these strings; new values will be on the heap.
715 // If process_tpd() preserves the content of such a string (e.g. ets_name),
716 // it must nevertheless make a copy on the heap via mcopystr().
717 static tpd_result
process_tpd_internal(const char *p_tpd_name
, char *tpdName
, const char *actcfg
,
718 const char *file_list_path
, int *p_argc
, char ***p_argv
,
719 int *p_optind
, char **p_ets_name
, char **p_project_name
,
720 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
721 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
722 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
723 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
724 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
725 struct string_list
* ttcn3_prep_defines
, struct string_list
* ttcn3_prep_undefines
, struct string_list
* prep_includes
,
726 struct string_list
* prep_defines
, struct string_list
* prep_undefines
, boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
,
727 char** cxxcompiler
, char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
,
728 boolean
* p_djflag
, boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
729 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, boolean
* p_Mflag
, boolean
* p_Eflag
, boolean
* p_nflag
,
730 boolean
* p_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
731 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
732 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
, boolean
*p_Zflag
,
733 boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
734 struct string2_list
* run_command_list
, map
<cstring
, int>& seen_tpd_files
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
735 const char **search_paths
, size_t n_search_paths
)
737 tpd_result result
= TPD_SUCCESS
;
738 // read-only non-pointer aliases
739 //char** const& local_argv = *p_argv;
740 int const& local_argc
= *p_argc
;
741 int const& local_optind
= *p_optind
;
742 *abs_work_dir_p
= NULL
;
744 assert(local_optind
>= 2 // at least '-ttpd_name' must be in the args
745 || local_optind
== 0); // if called for a referenced project
747 assert(local_argc
>= local_optind
);
749 autostring
tpd_dir(get_dir_from_path(p_tpd_name
));
750 autostring
abs_tpd_dir(get_absolute_dir(tpd_dir
, NULL
, FALSE
));
751 boolean free_name
= FALSE
;
753 //Only referenced project, when first try is failed, and when not absolute path
754 if(0 == local_optind
&& p_tpd_name
!= NULL
&& stat(p_tpd_name
, &buf
) && tpdName
!= NULL
) {
755 //Find the first search_path that has the tpd
756 for(size_t i
= 0; i
<n_search_paths
; i
++) {
757 boolean need_slash
= search_paths
[i
][strlen(search_paths
[i
]) - 1] != '/';
758 NOTIFY("Cannot find %s, trying with %s%s%s\n", p_tpd_name
, search_paths
[i
], need_slash
? "/" : "", tpdName
);
760 char * prefixed_file_path
= (char*)Malloc((strlen(search_paths
[i
]) + strlen(tpdName
) + 1 + need_slash
) * sizeof(char));
761 strcpy(prefixed_file_path
, search_paths
[i
]);
763 strcat(prefixed_file_path
, "/");
765 strcat(prefixed_file_path
, tpdName
);
767 tpd_dir
= get_dir_from_path(prefixed_file_path
);
768 abs_tpd_dir
= get_absolute_dir(tpd_dir
, NULL
, FALSE
);
770 if(!stat(prefixed_file_path
, &buf
)){
772 p_tpd_name
= prefixed_file_path
;
774 NOTIFY("TPD with name %s found at %s.", tpdName
, search_paths
[i
]);
777 //tpd not found, continue search
779 Free(prefixed_file_path
);
782 //Error if tpd is not found in either search paths
783 if(NULL
== (const char*)abs_tpd_dir
) {
784 //Only write out the name in the error message (without .tpd)
785 tpdName
[strlen(tpdName
)-4] ='\0';
786 ERROR("Unable to find ReferencedProject with name: %s", (const char*)tpdName
);
791 if (NULL
== (const char*)abs_tpd_dir
) {
792 ERROR("absolute TPD directory could not be retrieved from %s", (const char*)tpd_dir
);
795 autostring
tpd_filename(get_file_from_path(p_tpd_name
));
796 autostring
abs_tpd_name(compose_path_name(abs_tpd_dir
, tpd_filename
));
798 if (seen_tpd_files
.has_key(abs_tpd_name
)) {
799 ++*seen_tpd_files
[abs_tpd_name
];
800 return TPD_SKIPPED
; // nothing to do
803 if (recursive
&& !prefix_workdir
) {
804 // check that this tpd file is not inside a directory of another tpd file
805 for (size_t i
= 0; i
< seen_tpd_files
.size(); ++i
) {
806 const cstring
& other_tpd_name
= seen_tpd_files
.get_nth_key(i
);
807 autostring
other_tpd_dir(get_dir_from_path((const char*)other_tpd_name
));
808 if (strcmp((const char*)abs_tpd_dir
,(const char*)other_tpd_dir
)==0) {
809 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
);
814 // mcopystr makes another copy for the map
815 seen_tpd_files
.add(cstring(mcopystr(abs_tpd_name
)), new int(1));
818 vector
<char> base_files
; // values Malloc'd but we pass them to the caller
820 XmlDoc
doc(xmlParseFile(p_tpd_name
));
822 fprintf(stderr
, "Error: unable to parse file \"%s\"\n", p_tpd_name
);
827 // try schema validation if tpd schema file was found
828 bool tpd_is_valid
= false;
829 const char* ttcn3_dir
= getenv("TTCN3_DIR");
831 size_t ttcn3_dir_len
= strlen(ttcn3_dir
);
832 bool ends_with_slash
= (ttcn3_dir_len
>0) && (ttcn3_dir
[ttcn3_dir_len
- 1]=='/');
833 expstring_t xsd_file_name
= mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir
, ends_with_slash
?"":"/");
834 autostring
xsd_file_name_as(xsd_file_name
);
835 if (get_path_status(xsd_file_name
)==PS_FILE
) {
836 if (validate_tpd(doc
, p_tpd_name
, xsd_file_name
)) {
838 NOTIFY("TPD file `%s' validated successfully with schema file `%s'", p_tpd_name
, xsd_file_name
);
841 ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name
);
844 ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
852 // Key is projectRelativePath, value is relativeURI or rawURI.
853 map
<cstring
, const char> files
; // values Malloc'd
854 map
<cstring
, const char> folders
; // values Malloc'd
855 // NOTE! files and folders must be local variables of process_tpd.
856 // This is because the keys (not the values) are owned by the XmlDoc.
858 map
<cstring
, const char> path_vars
;
860 XPathContext
xpathCtx(xmlXPathNewContext(doc
));
861 if (xpathCtx
== NULL
) {
862 fprintf(stderr
,"Error: unable to create new XPath context\n");
865 // Collect path variables
867 XPathObject
pathsObj(run_xpath(xpathCtx
,
868 "/TITAN_Project_File_Information/PathVariables/PathVariable"));
869 xmlNodeSetPtr nodes
= pathsObj
->nodesetval
;
871 const char *name
= 0, *value
= 0;
872 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
873 // nodes->nodeTab[i]->name === "PathVariable"
874 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
875 if (!strcmp((const char*)attr
->name
, "name")) {
876 name
= (const char*)attr
->children
->content
;
878 else if (!strcmp((const char*)attr
->name
, "value")) {
879 value
= (const char*)attr
->children
->content
;
882 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
886 if (name
&& value
) path_vars
.add(cstring(name
), value
);
887 else ERROR("A PathVariable must have both name and value");
888 } // next PathVariable
893 XPathObject
foldersObj(run_xpath(xpathCtx
,
894 "/TITAN_Project_File_Information/Folders/FolderResource"));
896 xmlNodeSetPtr nodes
= foldersObj
->nodesetval
;
897 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
898 // nodes->nodeTab[i]->name === "FolderResource"
899 const char *uri
= 0, *path
= 0, *raw
= 0;
901 // projectRelativePath is the path as it appears in Project Explorer (illusion)
902 // relativeURI is the actual location, relative to the project root (reality)
903 // rawURI is present if the relative path can not be calculated
905 // Theoretically these attributes could be in any order, loop over them
906 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
907 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
908 path
= (const char*)attr
->children
->content
;
910 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
911 uri
= (const char*)attr
->children
->content
;
913 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
914 raw
= (const char*)attr
->children
->content
;
917 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
922 ERROR("A FolderResource must have a projectRelativePath");
926 if (uri
== NULL
&& raw
== NULL
) {
927 ERROR("A FolderResource must have either relativeURI or rawURI");
930 // relativeURI wins over rawURI
931 folders
.add(cstring(path
), uri
? mcopystr(uri
) : cook(raw
, path_vars
));
932 // TODO uri: cut "file:", complain on anything else
933 } // next FolderResource
936 /////////////////////////////////////////////////////////////////////////////
938 char *projectNameXpath
= mprintf("/TITAN_Project_File_Information/ProjectName/text()");
939 XPathObject
projectNameObj(run_xpath(xpathCtx
, projectNameXpath
));
940 Free(projectNameXpath
);
941 if (projectNameObj
->nodesetval
&& projectNameObj
->nodesetval
->nodeNr
> 0) {
942 *p_project_name
= mcopystr((const char*)projectNameObj
->nodesetval
->nodeTab
[0]->content
);
943 projGenHelper
.addTarget(*p_project_name
);
944 projGenHelper
.setToplevelProjectName(*p_project_name
);
945 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
946 if (projDesc
) projDesc
->setProjectAbsTpdDir((const char*)abs_tpd_dir
);
949 /////////////////////////////////////////////////////////////////////////////
952 actcfg
= get_act_config(required_configs
,*p_project_name
);
954 if (actcfg
== NULL
) {
955 // Find out the active config
956 XPathObject
activeConfig(run_xpath(xpathCtx
,
957 "/TITAN_Project_File_Information/ActiveConfiguration/text()"));
958 if (activeConfig
->nodesetval
&& activeConfig
->nodesetval
->nodeNr
== 1) {
960 actcfg
= (const char*)activeConfig
->nodesetval
->nodeTab
[0]->content
;
964 if (actcfg
== NULL
) {
965 ERROR("Can not find the active build configuration.");
966 for (size_t i
= 0; i
< folders
.size(); ++i
) {
967 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
973 { // check if the active configuration exists
974 expstring_t xpathActCfg
= mprintf(
975 "/TITAN_Project_File_Information/Configurations/"
976 "Configuration[@name='%s']/text()", actcfg
);
977 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfg
));
980 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
982 ERROR("The active build configuration named '%s' does not exist",
984 for (size_t i
= 0; i
< folders
.size(); ++i
) {
985 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
991 // working directory stuff
994 const char* workdirFromTpd
= "bin"; // default value
995 char *workdirXpath
= mprintf(
996 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
997 "/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
999 XPathObject
workdirObj(run_xpath(xpathCtx
, workdirXpath
));
1001 if (workdirObj
->nodesetval
&& workdirObj
->nodesetval
->nodeNr
> 0) {
1002 workdirFromTpd
= (const char*)workdirObj
->nodesetval
->nodeTab
[0]->content
;
1004 if (prefix_workdir
) { // the working directory is: prjNameStr + "_" + workdirFromTpd
1005 const char* prjNameStr
= "unnamedproject";
1006 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
1007 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1008 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1010 workdir
= mprintf("%s_%s", prjNameStr
, workdirFromTpd
);
1012 workdir
= mcopystr(workdirFromTpd
);
1015 if (!folders
.has_key(workdir
)) {
1016 // Maybe the tpd was saved with the option "No info about work dir"
1017 folders
.add(workdir
, mcopystr(workdir
)); // fake it
1019 const char *real_workdir
= folders
[workdir
]; // This is relative to the location of the tpd file
1020 excluded_folders
.add(real_workdir
); // excluded by convention
1022 autostring proj_abs_workdir
;
1024 autostring abs_workdir
;
1025 // If -D flag was specified then we ignore the workdir
1026 // in the TPD (the current dir is considered the work dir).
1028 bool hasWorkDir
= false;
1029 // if the working directory does not exist create it
1030 autostring
saved_work_dir(get_working_dir());
1031 if (set_working_dir(abs_tpd_dir
)) {
1032 ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir
);
1034 switch (get_path_status(real_workdir
)) {
1036 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
);
1043 if (recursive
|| local_argc
!= 0) { // we only want to create workdir if necessary
1044 fprintf(stderr
, "Working directory `%s' in project `%s' does not exist, trying to create it...\n",
1045 real_workdir
, (const char*)abs_tpd_dir
);
1046 int rv
= mkdir(real_workdir
, 0755);
1047 if (rv
) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno
));
1048 else printf("Working directory created\n");
1054 if (local_argc
==0) { // if not top level
1055 set_working_dir(saved_work_dir
); // restore working directory
1056 } else { // if top level
1057 set_working_dir(real_workdir
); // go into the working dir
1059 if (hasWorkDir
) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
1060 *abs_work_dir_p
= get_absolute_dir(real_workdir
, abs_tpd_dir
, TRUE
);
1061 abs_workdir
= (mcopystr(*abs_work_dir_p
));
1062 proj_abs_workdir
= mcopystr(*abs_work_dir_p
);
1066 if (Dflag
) { // the path to subproject working dir is needed to find the linkerlibsearchpath
1067 proj_abs_workdir
= compose_path_name(abs_tpd_dir
, real_workdir
);
1070 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1072 projDesc
->setProjectAbsWorkingDir((const char*)proj_abs_workdir
);
1073 projDesc
->setProjectWorkingDir(real_workdir
);
1074 projDesc
->setTPDFileName(p_tpd_name
);
1077 /////////////////////////////////////////////////////////////////////////////
1079 // Gather the excluded folders in the active config
1081 expstring_t xpathActCfgPaths
= mprintf(
1082 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1083 "/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
1084 // This was the selection criterium, we need to go up and down for the actual information
1085 "/parent::*/parent::*/FolderPath/text()",
1087 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
1088 Free(xpathActCfgPaths
);
1090 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
1091 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1093 excluded_folders
.add((const char*)nodes
->nodeTab
[i
]->content
);
1097 // Gather individual excluded files in the active config
1099 expstring_t xpathActCfgPaths
= mprintf(
1100 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1101 "/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
1102 "/parent::*/parent::*/FilePath/text()",
1104 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
1105 Free(xpathActCfgPaths
);
1107 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
1108 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1109 xmlNodePtr curnode
= nodes
->nodeTab
[i
];
1110 cstring
aa((const char*)curnode
->content
);
1111 if (!excluded_files
.has_key(aa
)) {
1112 excluded_files
.add(aa
, *p_project_name
);
1114 WARNING("Multiple exclusion of file %s", (const char*)curnode
->content
);
1119 // Collect files; filter out excluded ones
1121 XPathObject
filesObj(run_xpath(xpathCtx
,
1122 "TITAN_Project_File_Information/Files/FileResource"));
1124 xmlNodeSetPtr nodes
= filesObj
->nodesetval
;
1125 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1126 // nodes->nodeTab[i]->name === "FileResource"
1127 const char *uri
= 0, *path
= 0, *raw
= 0;
1129 // projectRelativePath is the path as it appears in Project Explorer (illusion)
1130 // relativeURI is the actual location, relative to the project root (reality)
1131 // rawURI is present if the relative path can not be calculated
1133 // Theoretically these attributes could be in any order, loop over them
1134 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
1135 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
1136 path
= (const char*)attr
->children
->content
;
1138 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
1139 uri
= (const char*)attr
->children
->content
;
1141 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
1142 raw
= (const char*)attr
->children
->content
;
1145 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
1150 ERROR("A FileResource must have a projectRelativePath");
1154 if (uri
== NULL
&& raw
== NULL
) {
1155 ERROR("A FileResource must have either relativeURI or rawURI");
1159 cstring
cpath(path
);
1160 if (!is_excluded_file(cpath
, *p_project_name
) && !is_excluded_folder(path
)) {
1161 // relativeURI wins over rawURI
1162 char *ruri
= uri
? mcopystr(uri
) : cook(raw
, path_vars
);
1163 if (files
.has_key(cpath
)) {
1164 ERROR("A FileResource %s must be unique!", (const char*)cpath
);
1168 const char* file_path
= ruri
;
1169 expstring_t rel_file_dir
= get_dir_from_path(file_path
);
1170 expstring_t file_name
= get_file_from_path(file_path
);
1171 expstring_t abs_dir_path
= get_absolute_dir(rel_file_dir
, abs_tpd_dir
, TRUE
);
1172 expstring_t abs_file_name
= compose_path_name(abs_dir_path
, file_name
);
1173 if (abs_file_name
!= NULL
) {
1174 if (get_path_status(abs_file_name
) == PS_FILE
) {
1175 FILE *fp
= fopen(abs_file_name
, "r");
1177 char* ttcn3_module_name
;
1178 if (is_ttcn3_module(abs_file_name
, fp
, &ttcn3_module_name
)) {
1179 projGenHelper
.addTtcn3ModuleToProject(*p_project_name
, ttcn3_module_name
);
1181 Free(ttcn3_module_name
);
1182 char* asn1_module_name
;
1183 if (is_asn1_module(abs_file_name
, fp
, &asn1_module_name
)) {
1184 projGenHelper
.addAsn1ModuleToProject(*p_project_name
, asn1_module_name
);
1186 Free(asn1_module_name
);
1187 if (projGenHelper
.isCPPSourceFile(file_name
)) {
1188 projGenHelper
.addUserSourceToProject(*p_project_name
, file_name
);
1190 if (projGenHelper
.isCPPHeaderFile(file_name
)) {
1191 projGenHelper
.addUserHeaderToProject(*p_project_name
, file_name
);
1193 if (projGenHelper
.isTtcnPPFile(file_name
)) {
1194 projGenHelper
.addTtcnPPToProject(*p_project_name
, file_name
);
1200 ERROR("%s does not exist", abs_file_name
);
1203 if(abs_dir_path
!= NULL
&& !drop
){
1204 files
.add(cpath
, ruri
); // relativeURI to the TPD location
1207 result
= TPD_FAILED
;
1209 { // set the *preprocess value if .ttcnpp file was found
1210 const size_t ttcnpp_extension_len
= 7; // ".ttcnpp"
1211 const size_t ruri_len
= strlen(ruri
);
1212 if ( ruri_len
>ttcnpp_extension_len
&& strcmp(ruri
+(ruri_len
-ttcnpp_extension_len
),".ttcnpp")==0 ) {
1219 Free(abs_file_name
);
1222 } // next FileResource
1226 xsdbool2boolean(xpathCtx
, actcfg
, "useAbsolutePath", p_aflag
);
1227 xsdbool2boolean(xpathCtx
, actcfg
, "GNUMake", p_gflag
);
1228 if (*p_Zflag
) *p_lflag
= FALSE
;
1229 xsdbool2boolean(xpathCtx
, actcfg
, "dynamicLinking", p_lflag
);
1230 xsdbool2boolean(xpathCtx
, actcfg
, "functiontestRuntime", p_Rflag
);
1231 xsdbool2boolean(xpathCtx
, actcfg
, "singleMode", p_sflag
);
1232 xsdbool2boolean(xpathCtx
, actcfg
, "codeSplitting", p_csflag
);
1233 xsdbool2boolean(xpathCtx
, actcfg
, "quietly", p_quflag
);
1234 xsdbool2boolean(xpathCtx
, actcfg
, "disableSubtypeChecking", p_dsflag
);
1235 xsdbool2boolean(xpathCtx
, actcfg
, "disableBER", p_dbflag
);
1236 xsdbool2boolean(xpathCtx
, actcfg
, "disableRAW", p_drflag
);
1237 xsdbool2boolean(xpathCtx
, actcfg
, "disableTEXT", p_dtflag
);
1238 xsdbool2boolean(xpathCtx
, actcfg
, "disableXER", p_dxflag
);
1239 xsdbool2boolean(xpathCtx
, actcfg
, "disableJSON", p_djflag
);
1240 xsdbool2boolean(xpathCtx
, actcfg
, "forceXERinASN.1", p_fxflag
);
1241 xsdbool2boolean(xpathCtx
, actcfg
, "defaultasOmit", p_doflag
);
1242 xsdbool2boolean(xpathCtx
, actcfg
, "gccMessageFormat", p_gfflag
);
1243 xsdbool2boolean(xpathCtx
, actcfg
, "lineNumbersOnlyInMessages", p_lnflag
);
1244 xsdbool2boolean(xpathCtx
, actcfg
, "includeSourceInfo", p_isflag
);
1245 xsdbool2boolean(xpathCtx
, actcfg
, "addSourceLineInfo", p_asflag
);
1246 xsdbool2boolean(xpathCtx
, actcfg
, "suppressWarnings", p_swflag
);
1247 xsdbool2boolean(xpathCtx
, actcfg
, "outParamBoundness", p_Yflag
); //not documented, obsolete
1248 xsdbool2boolean(xpathCtx
, actcfg
, "forceOldFuncOutParHandling", p_Yflag
);
1249 xsdbool2boolean(xpathCtx
, actcfg
, "omitInValueList", p_Mflag
);
1250 xsdbool2boolean(xpathCtx
, actcfg
, "warningsForBadVariants", p_Eflag
);
1251 xsdbool2boolean(xpathCtx
, actcfg
, "activateDebugger", p_nflag
);
1252 xsdbool2boolean(xpathCtx
, actcfg
, "disablePredefinedExternalFolder", p_diflag
);
1254 projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1255 if (projDesc
) projDesc
->setLinkingStrategy(*p_lflag
);
1257 // Extract the "incremental dependencies" option
1259 boolean incremental_deps
= TRUE
;
1260 xsdbool2boolean(xpathCtx
, actcfg
, "incrementalDependencyRefresh", &incremental_deps
);
1262 // For makefilegen, "Use GNU make" implies incremental deps by default,
1263 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
1264 // For Eclipse, incremental deps must be explicitly specified,
1265 // even if GNU make is being used.
1267 if (incremental_deps
) {
1269 WARNING("Incremental dependency ordered but it requires gnu make");
1274 // GNU make but no incremental deps
1280 // Extract the default target option
1281 // if it is not defined as a command line argument
1283 expstring_t defTargetXpath
= mprintf(
1284 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1285 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
1287 XPathObject
defTargetObj(run_xpath(xpathCtx
, defTargetXpath
));
1288 Free(defTargetXpath
);
1289 if (defTargetObj
->nodesetval
&& defTargetObj
->nodesetval
->nodeNr
> 0) {
1290 const char* content
= (const char*)defTargetObj
->nodesetval
->nodeTab
[0]->content
;
1291 if (!strcmp(content
, "library")) {
1293 } else if (!strcmp(content
, "executable")) {
1296 ERROR("Unknown default target: '%s'."
1297 " The available targets are: 'executable', 'library'", content
);
1300 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1301 if (projDesc
) projDesc
->setLibrary(*p_Lflag
);
1304 // Executable name (don't care unless top-level invocation)
1305 if (local_argc
!= 0)
1307 char *exeXpath
= mprintf(
1308 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1309 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
1311 XPathObject
exeObj(run_xpath(xpathCtx
, exeXpath
));
1313 if (exeObj
->nodesetval
&& exeObj
->nodesetval
->nodeNr
> 0) {
1314 const char* target_executable
= (const char*)exeObj
->nodesetval
->nodeTab
[0]->content
;
1315 autostring
target_exe_dir(get_dir_from_path(target_executable
));
1316 autostring
target_exe_file(get_file_from_path(target_executable
));
1317 if (target_exe_dir
!=NULL
) { // if it's not only a file name
1318 if (get_path_status(target_exe_dir
)==PS_NONEXISTENT
) {
1319 if (strcmp(real_workdir
,target_exe_dir
)!=0) {
1320 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
);
1322 target_executable
= target_exe_file
;
1325 if (!*p_ets_name
) { // Command line will win
1326 *p_ets_name
= mcopystr(target_executable
);
1331 // create an xml element for the currently processed project
1333 const char* prjNameStr
= "???";
1334 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
1335 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1336 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1338 autostring
tpd_rel_dir(get_relative_dir(tpd_dir
, NULL
));
1339 autostring
tpd_rel_path(compose_path_name(tpd_rel_dir
, (const char*)tpd_filename
));
1340 fprintf(prj_graph_fp
, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr
, (const char*)tpd_rel_path
);
1341 XPathObject
subprojects(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
1342 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
1343 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1344 const char* refd_name
= "???";
1345 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1346 refd_name
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1348 fprintf(prj_graph_fp
, "<reference name=\"%s\"/>\n", refd_name
);
1350 fprintf(prj_graph_fp
, "</project>\n");
1353 // Tpd part of the MakefileSettings
1355 //TTCN3preprocessorIncludes
1356 char *preincludeXpath
= mprintf(
1357 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1358 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
1360 XPathObject
preincludeObj(run_xpath(xpathCtx
, preincludeXpath
));
1361 Free(preincludeXpath
);
1363 xmlNodeSetPtr nodes
= preincludeObj
->nodesetval
;
1365 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1366 char* content
= (char*)preincludeObj
->nodesetval
->nodeTab
[i
]->content
;
1368 // add includes to the end of list
1369 if (ttcn3_prep_includes
) {
1370 // go to last element
1371 struct string_list
* last_elem
= ttcn3_prep_includes
;
1372 while (last_elem
->next
) last_elem
= last_elem
->next
;
1373 // add string to last element if empty or create new last element and add it to that
1374 if (last_elem
->str
) {
1375 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1376 last_elem
= last_elem
->next
;
1377 last_elem
->next
= NULL
;
1379 replacechar(&content
);
1380 last_elem
->str
= content
;
1385 //TTCN3preprocessorDefines
1386 char *ttcn3predefinesXpath
= mprintf(
1387 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1388 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
1390 XPathObject
ttcn3predefinesObj(run_xpath(xpathCtx
, ttcn3predefinesXpath
));
1391 Free(ttcn3predefinesXpath
);
1393 xmlNodeSetPtr nodes
= ttcn3predefinesObj
->nodesetval
;
1395 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1396 const char* content
= (const char*)ttcn3predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1398 // add includes to the end of list
1399 if (ttcn3_prep_defines
) {
1400 // go to last element
1401 struct string_list
* last_elem
= ttcn3_prep_defines
;
1402 while (last_elem
->next
) last_elem
= last_elem
->next
;
1403 // add string to last element if empty or create new last element and add it to that
1404 if (last_elem
->str
) {
1405 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1406 last_elem
= last_elem
->next
;
1407 last_elem
->next
= NULL
;
1409 last_elem
->str
= mcopystr(content
);
1414 //TTCN3preprocessorUnDefines
1415 char *ttcn3preUndefinesXpath
= mprintf(
1416 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1417 "/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()",
1419 XPathObject
ttcn3preUndefinesObj(run_xpath(xpathCtx
, ttcn3preUndefinesXpath
));
1420 Free(ttcn3preUndefinesXpath
);
1422 xmlNodeSetPtr nodes
= ttcn3preUndefinesObj
->nodesetval
;
1424 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1425 const char* content
= (const char*)ttcn3preUndefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1427 // add includes to the end of list
1428 if (ttcn3_prep_undefines
) {
1429 // go to last element
1430 struct string_list
* last_elem
= ttcn3_prep_undefines
;
1431 while (last_elem
->next
) last_elem
= last_elem
->next
;
1432 // add string to last element if empty or create new last element and add it to that
1433 if (last_elem
->str
) {
1434 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1435 last_elem
= last_elem
->next
;
1436 last_elem
->next
= NULL
;
1438 last_elem
->str
= mcopystr(content
);
1444 //preprocessorIncludes
1445 char *preincludesXpath
= mprintf(
1446 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1447 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
1449 XPathObject
preincludesObj(run_xpath(xpathCtx
, preincludesXpath
));
1450 Free(preincludesXpath
);
1452 xmlNodeSetPtr nodes
= preincludesObj
->nodesetval
;
1454 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1455 char* content
= (char*)preincludesObj
->nodesetval
->nodeTab
[i
]->content
;
1457 // add includes to the end of list
1458 if (prep_includes
) {
1459 // go to last element
1460 struct string_list
* last_elem
= prep_includes
;
1461 while (last_elem
->next
) last_elem
= last_elem
->next
;
1462 // add string to last element if empty or create new last element and add it to that
1463 if (last_elem
->str
) {
1464 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1465 last_elem
= last_elem
->next
;
1466 last_elem
->next
= NULL
;
1468 replacechar(&content
);
1469 last_elem
->str
= content
;
1474 //preprocessorDefines
1475 char *predefinesXpath
= mprintf(
1476 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1477 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
1479 XPathObject
predefinesObj(run_xpath(xpathCtx
, predefinesXpath
));
1480 Free(predefinesXpath
);
1482 xmlNodeSetPtr nodes
= predefinesObj
->nodesetval
;
1484 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1485 const char* content
= (const char*)predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1487 // add includes to the end of list
1489 // go to last element
1490 struct string_list
* last_elem
= prep_defines
;
1491 while (last_elem
->next
) last_elem
= last_elem
->next
;
1492 // add string to last element if empty or create new last element and add it to that
1493 if (last_elem
->str
) {
1494 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1495 last_elem
= last_elem
->next
;
1496 last_elem
->next
= NULL
;
1498 last_elem
->str
= mcopystr(content
);
1503 //preprocessorUnDefines
1504 char *preUndefinesXpath
= mprintf(
1505 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1506 "/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()",
1508 XPathObject
preUndefinesObj(run_xpath(xpathCtx
, preUndefinesXpath
));
1509 Free(preUndefinesXpath
);
1511 xmlNodeSetPtr nodes
= preUndefinesObj
->nodesetval
;
1513 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1514 const char* content
= (const char*)preUndefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1516 // add includes to the end of list
1517 if (prep_undefines
) {
1518 // go to last element
1519 struct string_list
* last_elem
= prep_undefines
;
1520 while (last_elem
->next
) last_elem
= last_elem
->next
;
1521 // add string to last element if empty or create new last element and add it to that
1522 if (last_elem
->str
) {
1523 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1524 last_elem
= last_elem
->next
;
1525 last_elem
->next
= NULL
;
1527 last_elem
->str
= mcopystr(content
);
1532 char *cxxCompilerXpath
= mprintf(
1533 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1534 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1536 XPathObject
cxxCompilerObj(run_xpath(xpathCtx
, cxxCompilerXpath
));
1537 Free(cxxCompilerXpath
);
1538 xmlNodeSetPtr nodes
= cxxCompilerObj
->nodesetval
;
1540 *cxxcompiler
= mcopystr((const char*)cxxCompilerObj
->nodesetval
->nodeTab
[0]->content
);
1544 char *optLevelXpath
= mprintf(
1545 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1546 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1548 XPathObject
optLevelObj(run_xpath(xpathCtx
, optLevelXpath
));
1549 Free(optLevelXpath
);
1550 xmlNodeSetPtr nodes
= optLevelObj
->nodesetval
;
1552 *optlevel
= mcopystr((const char*)optLevelObj
->nodesetval
->nodeTab
[0]->content
);
1556 char *optFlagsXpath
= mprintf(
1557 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1558 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1560 XPathObject
optFlagsObj(run_xpath(xpathCtx
, optFlagsXpath
));
1561 Free(optFlagsXpath
);
1562 xmlNodeSetPtr nodes
= optFlagsObj
->nodesetval
;
1564 *optflags
= mcopystr((const char*)optFlagsObj
->nodesetval
->nodeTab
[0]->content
);
1568 //SolarisSpecificLibraries
1569 char *solspeclibXpath
= mprintf(
1570 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1571 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1573 XPathObject
solspeclibObj(run_xpath(xpathCtx
, solspeclibXpath
));
1574 Free(solspeclibXpath
);
1576 xmlNodeSetPtr nodes
= solspeclibObj
->nodesetval
;
1578 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1579 char* content
= (char*)solspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1581 // add includes to the end of list
1583 // go to last element
1584 struct string_list
* last_elem
=solspeclibs
;
1585 while (last_elem
->next
) last_elem
= last_elem
->next
;
1586 // add string to last element if empty or create new last element and add it to that
1587 if (last_elem
->str
) {
1588 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1589 last_elem
= last_elem
->next
;
1590 last_elem
->next
= NULL
;
1592 replacechar(&content
);
1593 last_elem
->str
= content
;
1598 //Solaris8SpecificLibraries
1599 char *sol8speclibXpath
= mprintf(
1600 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1601 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1603 XPathObject
sol8speclibObj(run_xpath(xpathCtx
, sol8speclibXpath
));
1604 Free(sol8speclibXpath
);
1606 xmlNodeSetPtr nodes
= sol8speclibObj
->nodesetval
;
1608 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1609 char* content
= (char*)sol8speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1611 // add includes to the end of list
1613 // go to last element
1614 struct string_list
* last_elem
= sol8speclibs
;
1615 while (last_elem
->next
) last_elem
= last_elem
->next
;
1616 // add string to last element if empty or create new last element and add it to that
1617 if (last_elem
->str
) {
1618 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1619 last_elem
= last_elem
->next
;
1620 last_elem
->next
= NULL
;
1622 replacechar(&content
);
1623 last_elem
->str
= content
;
1628 //LinuxSpecificLibraries
1629 char *linuxspeclibXpath
= mprintf(
1630 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1631 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1633 XPathObject
linuxspeclibObj(run_xpath(xpathCtx
, linuxspeclibXpath
));
1634 Free(linuxspeclibXpath
);
1636 xmlNodeSetPtr nodes
= linuxspeclibObj
->nodesetval
;
1638 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1639 char* content
= (char*)linuxspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1641 // add includes to the end of list
1642 if (linuxspeclibs
) {
1643 // go to last element
1644 struct string_list
* last_elem
= linuxspeclibs
;
1645 while (last_elem
->next
) last_elem
= last_elem
->next
;
1646 // add string to last element if empty or create new last element and add it to that
1647 if (last_elem
->str
) {
1648 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1649 last_elem
= last_elem
->next
;
1650 last_elem
->next
= NULL
;
1652 replacechar(&content
);
1653 last_elem
->str
= content
;
1658 //FreeBSDSpecificLibraries
1659 char *freebsdspeclibXpath
= mprintf(
1660 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1661 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1663 XPathObject
freebsdspeclibObj(run_xpath(xpathCtx
, freebsdspeclibXpath
));
1664 Free(freebsdspeclibXpath
);
1666 xmlNodeSetPtr nodes
= freebsdspeclibObj
->nodesetval
;
1668 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1669 char* content
= (char*)freebsdspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1671 // add includes to the end of list
1672 if (freebsdspeclibs
) {
1673 // go to last element
1674 struct string_list
* last_elem
= freebsdspeclibs
;
1675 while (last_elem
->next
) last_elem
= last_elem
->next
;
1676 // add string to last element if empty or create new last element and add it to that
1677 if (last_elem
->str
) {
1678 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1679 last_elem
= last_elem
->next
;
1680 last_elem
->next
= NULL
;
1682 replacechar(&content
);
1683 last_elem
->str
= content
;
1688 //Win32SpecificLibraries
1689 char *win32speclibXpath
= mprintf(
1690 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1691 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1693 XPathObject
win32speclibObj(run_xpath(xpathCtx
, win32speclibXpath
));
1694 Free(win32speclibXpath
);
1696 xmlNodeSetPtr nodes
= win32speclibObj
->nodesetval
;
1698 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1699 char* content
= (char*)win32speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1701 // add includes to the end of list
1702 if (win32speclibs
) {
1703 // go to last element
1704 struct string_list
* last_elem
= win32speclibs
;
1705 while (last_elem
->next
) last_elem
= last_elem
->next
;
1706 // add string to last element if empty or create new last element and add it to that
1707 if (last_elem
->str
) {
1708 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1709 last_elem
= last_elem
->next
;
1710 last_elem
->next
= NULL
;
1712 replacechar(&content
);
1713 last_elem
->str
= content
;
1720 char *ttcn3preproc
= mprintf(
1721 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1722 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1724 XPathObject
ttcn3preprocObj(run_xpath(xpathCtx
, ttcn3preproc
));
1726 xmlNodeSetPtr nodes
= ttcn3preprocObj
->nodesetval
;
1728 *ttcn3prep
= mcopystr((const char*)ttcn3preprocObj
->nodesetval
->nodeTab
[0]->content
);
1732 // additionalObjects
1733 char *additionalObjectsXpath
= mprintf(
1734 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1735 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1737 XPathObject
additionalObjectsObj(run_xpath(xpathCtx
, additionalObjectsXpath
));
1738 Free(additionalObjectsXpath
);
1740 xmlNodeSetPtr nodes
= additionalObjectsObj
->nodesetval
;
1742 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1743 char* content
= (char*)additionalObjectsObj
->nodesetval
->nodeTab
[i
]->content
;
1745 // add to the end of list
1746 if (additionalObjects
) {
1747 // go to last element
1748 struct string_list
* last_elem
= additionalObjects
;
1749 while (last_elem
->next
) last_elem
= last_elem
->next
;
1750 // add string to last element if empty or create new last element and add it to that
1751 if (last_elem
->str
) {
1752 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1753 last_elem
= last_elem
->next
;
1754 last_elem
->next
= NULL
;
1756 replacechar(&content
);
1757 last_elem
->str
= content
;
1762 //The project name needed the hierarchical projects
1763 char* prjNameStr
= 0;
1764 char *prjNameStrXpath
= mprintf("/TITAN_Project_File_Information/ProjectName/text()");
1765 XPathObject
prjName(run_xpath(xpathCtx
, prjNameStrXpath
));
1766 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1767 prjNameStr
= (char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1769 Free(prjNameStrXpath
);
1770 append_to_library_list (prjNameStr
, xpathCtx
, actcfg
);
1773 char *linkerlibsXpath
= mprintf(
1774 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1775 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1777 XPathObject
linkerlibsObj(run_xpath(xpathCtx
, linkerlibsXpath
));
1778 Free(linkerlibsXpath
);
1780 xmlNodeSetPtr nodes
= linkerlibsObj
->nodesetval
;
1782 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1783 char* content
= (char*)linkerlibsObj
->nodesetval
->nodeTab
[i
]->content
;
1785 // add includes to the end of list
1787 // go to last element
1788 struct string_list
* last_elem
= linkerlibs
;
1789 while (last_elem
->next
) last_elem
= last_elem
->next
;
1790 // add string to last element if empty or create new last element and add it to that
1791 if (last_elem
->str
) {
1792 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1793 last_elem
= last_elem
->next
;
1794 last_elem
->next
= NULL
;
1796 replacechar(&content
);
1797 last_elem
->str
= content
;
1799 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1800 if (projDesc
) projDesc
->addToLinkerLibs(last_elem
->str
);
1805 //linkerLibrarySearchPath
1806 char *linkerlibsearchXpath
= mprintf(
1807 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1808 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1810 XPathObject
linkerlibsearchObj(run_xpath(xpathCtx
, linkerlibsearchXpath
));
1811 Free(linkerlibsearchXpath
);
1813 xmlNodeSetPtr nodes
= linkerlibsearchObj
->nodesetval
;
1815 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1816 char* content
= (char*)linkerlibsearchObj
->nodesetval
->nodeTab
[i
]->content
;
1818 // add includes to the end of list
1819 if (linkerlibsearchp
) {
1820 // go to last element
1821 struct string_list
* last_elem
= linkerlibsearchp
;
1822 while (last_elem
->next
) last_elem
= last_elem
->next
;
1823 // add string to last element if empty or create new last element and add it to that
1824 if (last_elem
->str
) {
1825 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1826 last_elem
= last_elem
->next
;
1827 last_elem
->next
= NULL
;
1829 replacechar(&content
);
1830 last_elem
->str
= content
;
1832 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1833 if (projDesc
) projDesc
->addToLibSearchPaths(last_elem
->str
);
1838 if (generatorCommandOutput
&& local_argc
!= 0) { // only in case of top-level invocation
1839 char* generatorCommandXpath
= mprintf(
1840 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1841 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1843 XPathObject
generatorCommandObj(run_xpath(xpathCtx
, generatorCommandXpath
));
1844 Free(generatorCommandXpath
);
1845 autostring generatorCommand
;
1846 if (generatorCommandObj
->nodesetval
&& generatorCommandObj
->nodesetval
->nodeNr
> 0) {
1847 generatorCommand
= mcopystr((const char*)generatorCommandObj
->nodesetval
->nodeTab
[0]->content
);
1848 // run the command and capture the output
1849 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand
, (const char*)abs_tpd_name
);
1850 FILE* gc_fp
= popen(generatorCommand
, "r");
1852 ERROR("Could not execute command `%s'", (const char*)generatorCommand
);
1855 while (fgets(buff
, sizeof(buff
), gc_fp
)!=NULL
) {
1856 *generatorCommandOutput
= mputstr(*generatorCommandOutput
, buff
);
1863 if (target_placement_list
&& local_argc
!= 0) { // only in case of top-level invocation
1864 char* targetPlacementXpath
= mprintf(
1865 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1866 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1868 XPathObject
targetPlacementObj(run_xpath(xpathCtx
, targetPlacementXpath
));
1869 Free(targetPlacementXpath
);
1870 xmlNodeSetPtr nodes
= targetPlacementObj
->nodesetval
;
1871 const char* targetName
= NULL
;
1872 const char* targetPlacement
= NULL
;
1873 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1874 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1875 targetName
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1877 else if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
,"placement")) {
1878 targetPlacement
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1880 if (targetName
&& targetPlacement
) { // collected both
1881 if (target_placement_list
) {
1882 // go to last element
1883 struct string2_list
* last_elem
= target_placement_list
;
1884 while (last_elem
->next
) last_elem
= last_elem
->next
;
1885 // add strings to last element if empty or create new last element and add it to that
1886 if (last_elem
->str1
) {
1887 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
1888 last_elem
= last_elem
->next
;
1889 last_elem
->next
= NULL
;
1891 last_elem
->str1
= mcopystr(targetName
);
1892 last_elem
->str2
= mcopystr(targetPlacement
);
1894 targetName
= targetPlacement
= NULL
; // forget both
1900 // profiler file name
1901 char* profilerXpath
= mprintf(
1902 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1903 "/ProjectProperties/MakefileSettings/profiledFileList", actcfg
);
1904 XPathObject
profiledFilesNameObj(run_xpath(xpathCtx
, profilerXpath
));
1905 Free(profilerXpath
);
1906 xmlNodeSetPtr nodes
= profiledFilesNameObj
->nodesetval
;
1907 if (nodes
&& nodes
->nodeNr
> 0) {
1908 const char *uri
= 0, *path
= 0, *raw
= 0;
1909 for (xmlAttrPtr attr
= nodes
->nodeTab
[0]->properties
; attr
; attr
= attr
->next
) {
1910 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
1911 path
= (const char*)attr
->children
->content
;
1913 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
1914 uri
= (const char*)attr
->children
->content
;
1916 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
1917 raw
= (const char*)attr
->children
->content
;
1920 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[0]->name
);
1925 ERROR("A profiledFileList must have a projectRelativePath");
1928 if (uri
== NULL
&& raw
== NULL
) {
1929 ERROR("A profiledFileList must have either relativeURI or rawURI");
1932 cstring
cpath(path
);
1933 if (files
.has_key(cpath
)) {
1934 ERROR("profiledFileLists and FileResources must be unique!");
1937 // add the file to the end of the list
1938 struct string_list
* new_item
= NULL
;
1939 if (*profiled_file_list
== NULL
) {
1940 *profiled_file_list
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1941 new_item
= *profiled_file_list
;
1944 new_item
= *profiled_file_list
;
1945 while(new_item
->next
!= NULL
) {
1946 new_item
= new_item
->next
;
1948 new_item
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1949 new_item
= new_item
->next
;
1951 new_item
->str
= mcopystr(path
);
1952 new_item
->next
= NULL
;
1954 // add the file to the map of files to be copied to the working directory
1955 char *ruri
= uri
? mcopystr(uri
) : cook(raw
, path_vars
);
1956 files
.add(cpath
, ruri
);
1963 // collect the required configurations
1965 if (required_configs
) {
1966 char* cfgReqsXpath(mprintf(
1967 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1968 "/ProjectProperties/ConfigurationRequirements/configurationRequirement",
1970 XPathObject
reqcfgObjects(run_xpath(xpathCtx
, cfgReqsXpath
));
1971 Free (cfgReqsXpath
);
1972 xmlNodeSetPtr configs
= reqcfgObjects
->nodesetval
;
1973 if (configs
) for (int i
= 0; i
< configs
->nodeNr
; ++i
) {
1974 xmlNodePtr curNodePtr
= configs
->nodeTab
[i
]->children
;
1975 const char* projectName
= NULL
;
1976 const char* reqConfig
= NULL
;
1978 if (!strcmp((const char*)curNodePtr
->name
, "projectName")) {
1979 projectName
= (const char*)curNodePtr
->children
->content
;
1981 if (!strcmp((const char*)curNodePtr
->name
, "rerquiredConfiguration") || // backward compatibility
1982 !strcmp((const char*)curNodePtr
->name
, "requiredConfiguration")) {
1983 reqConfig
= (const char*)curNodePtr
->children
->content
;
1985 curNodePtr
= curNodePtr
->next
;
1987 struct string2_list
* last_elem
= required_configs
;
1988 bool duplicate
= false;
1989 while (last_elem
->next
) {
1990 if (!strcmp(last_elem
->str1
, projectName
) && !strcmp(last_elem
->str2
, reqConfig
)) {
1993 else if (!strcmp(last_elem
->str1
, projectName
) && strcmp(last_elem
->str2
, reqConfig
)) {
1994 ERROR("Required configuration is inconsistent : Project '%s' cannot have 2 "
1995 "different configuration '%s' '%s'",
1996 last_elem
->str1
, last_elem
->str2
, reqConfig
);
1997 result
= TPD_FAILED
;
1999 last_elem
= last_elem
->next
;
2001 // add string to last element if empty or create new last element and add it to that
2002 if (last_elem
->str1
&& !duplicate
) {
2003 if (strcmp(last_elem
->str1
, projectName
) || strcmp(last_elem
->str2
, reqConfig
)) {
2004 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2005 last_elem
= last_elem
->next
;
2006 last_elem
->next
= NULL
;
2013 last_elem
->str1
= mcopystr(projectName
);
2014 last_elem
->str2
= mcopystr(reqConfig
);
2020 // Referenced projects
2022 XPathObject
subprojects(run_xpath(xpathCtx
,
2023 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject"));
2024 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
2025 //Go through ReferencedProjects
2026 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
2027 const char *name
= NULL
, *projectLocationURI
= NULL
;
2028 char *tpdName_loc
= NULL
;
2029 // FIXME: this assumes every ReferencedProject has name and URI.
2030 // This is not necessarily so if the referenced project was closed
2031 // when the project was exported to TPD.
2032 // Luckily, the name from the closed project will be overwritten
2033 // by the name from the next ReferencedProject. However, if some pervert
2034 // changes the next ReferencedProject to have the projectLocationURI
2035 // as the first attribute, it will be joined to the name
2036 // of the previous, closed, ReferencedProject.
2038 //Go through attributes
2039 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
2040 if (!strcmp((const char*)attr
->name
, "name")) {
2041 name
= (const char*)attr
->children
->content
;
2043 else if (!strcmp((const char*)attr
->name
,"projectLocationURI")) {
2044 projectLocationURI
= (const char*)attr
->children
->content
;
2046 else if (!strcmp((const char*)attr
->name
, "tpdName")) {
2048 tpdName_loc
= mcopystr((char*)attr
->children
->content
);
2051 //We don't want to orerride an absolute location with -I, tpdName remains NULL
2052 boolean not_abs_path
= projectLocationURI
&&
2053 #if defined WIN32 && defined MINGW
2054 /* On native Windows the absolute path name shall begin with
2055 * a drive letter, colon and backslash */
2056 (((projectLocationURI
[0] < 'A' || projectLocationURI
[0] > 'Z') &&
2057 (projectLocationURI
[0] < 'a' || projectLocationURI
[0] > 'z')) ||
2058 projectLocationURI
[1] != ':' || projectLocationURI
[2] != '\\');
2060 /* On UNIX-like systems the absolute path name shall begin with
2062 projectLocationURI
[0] != '/';
2064 if (!tpdName_loc
&& not_abs_path
) {
2065 //Allocate memory: +5 because .tpd + closing 0
2066 tpdName_loc
= (char*)Malloc((strlen(name
) + 5) * sizeof(char));
2067 //Default name: name + .tpd
2068 strcpy(tpdName_loc
, name
);
2069 strcat(tpdName_loc
, ".tpd");
2070 }else if (!not_abs_path
) {
2075 if (name
&& projectLocationURI
) { // collected both
2076 // see if there is a specified configuration for the project
2078 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
2079 if (projDesc
) projDesc
->addToReferencedProjects(name
);
2081 const char *my_actcfg
= NULL
;
2083 char *my_args
[] = { NULL
};
2084 char **my_argv
= my_args
+ 0;
2086 boolean my_gflag
= *p_gflag
, my_aflag
= *p_aflag
, my_cflag
= *p_cflag
, // pass down
2087 my_Rflag
= *p_Rflag
, my_Pflag
= *p_Pflag
, my_Zflag
= *p_Zflag
, my_Hflag
= *p_Hflag
,
2088 my_sflag
= 0, my_Lflag
= 0, my_lflag
= 0, my_mflag
= 0, my_csflag
= 0,
2089 my_quflag
= 0, my_dsflag
= 0, my_dbflag
= 0, my_drflag
= 0,
2090 my_dtflag
= 0, my_dxflag
= 0, my_djflag
= 0, my_fxflag
= 0, my_doflag
= 0,
2091 my_gfflag
= 0, my_lnflag
= 0, my_isflag
= 0, my_asflag
= 0,
2092 my_swflag
= 0, my_Yflag
= 0, my_Mflag
= *p_Mflag
, my_Eflag
= 0, my_nflag
= *p_nflag
,
2093 my_diflag
= *p_diflag
;
2095 char *my_ets
= NULL
;
2096 char *my_proj_name
= NULL
;
2097 autostring abs_projectLocationURI
;
2099 abs_projectLocationURI
= compose_path_name(abs_tpd_dir
, projectLocationURI
);
2101 //If absolute directory, then just copy the URI
2102 abs_projectLocationURI
= mcopystr(projectLocationURI
);
2105 char* sub_proj_abs_work_dir
= NULL
;
2107 tpd_result success
= process_tpd_internal((const char*)abs_projectLocationURI
, tpdName_loc
,
2108 my_actcfg
, file_list_path
, &my_argc
, &my_argv
, &my_optind
, &my_ets
, &my_proj_name
,
2109 &my_gflag
, &my_sflag
, &my_cflag
, &my_aflag
, preprocess
, &my_Rflag
, &my_lflag
,
2110 &my_mflag
, &my_Pflag
, &my_Lflag
, recursive
, force_overwrite
, gen_only_top_level
, NULL
, &sub_proj_abs_work_dir
,
2111 sub_project_dirs
, program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
, ttcn3_prep_defines
, ttcn3_prep_undefines
,
2112 prep_includes
, prep_defines
, prep_undefines
, &my_csflag
,
2113 &my_quflag
, &my_dsflag
, cxxcompiler
, optlevel
, optflags
, &my_dbflag
, &my_drflag
,
2114 &my_dtflag
, &my_dxflag
, &my_djflag
, &my_fxflag
, &my_doflag
,
2115 &my_gfflag
, &my_lnflag
, &my_isflag
, &my_asflag
, &my_swflag
, &my_Yflag
, &my_Mflag
, &my_Eflag
, &my_nflag
, &my_diflag
,
2116 solspeclibs
, sol8speclibs
, linuxspeclibs
, freebsdspeclibs
, win32speclibs
,
2117 ttcn3prep
, linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, FALSE
, &my_Zflag
,
2118 &my_Hflag
, NULL
, NULL
, prefix_workdir
, run_command_list
, seen_tpd_files
, required_configs
, profiled_file_list
,
2119 search_paths
, n_search_paths
);
2121 autostring
sub_proj_abs_work_dir_as(sub_proj_abs_work_dir
); // ?!
2123 if (success
== TPD_SUCCESS
) {
2124 my_actcfg
= get_act_config(required_configs
, my_proj_name
);
2125 if (recursive
) { // call ttcn3_makefilegen on referenced project's tpd file
2126 // -r is not needed any more because top level process traverses all projects recursively
2127 expstring_t command
= mprintf("%s -cVD", program_name
);
2128 if (force_overwrite
) command
= mputc(command
, 'f');
2129 if (prefix_workdir
) command
= mputc(command
, 'W');
2130 if (*p_gflag
) command
= mputc(command
, 'g');
2131 if (*p_sflag
) command
= mputc(command
, 's');
2132 if (*p_aflag
) command
= mputc(command
, 'a');
2133 if (*p_Rflag
) command
= mputc(command
, 'R');
2134 if (*p_lflag
) command
= mputc(command
, 'l');
2135 if (*p_mflag
) command
= mputc(command
, 'm');
2136 if (*p_Zflag
) command
= mputc(command
, 'Z');
2137 if (*p_Hflag
) command
= mputc(command
, 'H');
2138 command
= mputstr(command
, " -t ");
2139 command
= mputstr(command
, (const char*)abs_projectLocationURI
);
2141 command
= mputstr(command
, " -b ");
2142 command
= mputstr(command
, my_actcfg
);
2145 autostring
sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI
));
2146 const char * sub_proj_effective_work_dir
= sub_proj_abs_work_dir
? sub_proj_abs_work_dir
: (const char*)sub_tpd_dir
;
2147 if (!gen_only_top_level
) {
2148 if (run_command_list
) {
2149 // go to last element
2150 struct string2_list
* last_elem
= run_command_list
;
2151 while (last_elem
->next
) last_elem
= last_elem
->next
;
2152 // add strings to last element if empty or create new last element and add it to that
2153 if (last_elem
->str1
|| last_elem
->str2
) {
2154 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2155 last_elem
= last_elem
->next
;
2156 last_elem
->next
= NULL
;
2158 last_elem
->str1
= mcopystr(sub_proj_effective_work_dir
);
2159 last_elem
->str2
= command
;
2161 ERROR("Internal error: cannot add command to list");
2164 // add working dir to the end of list
2165 if (sub_project_dirs
) {
2166 // go to last element
2167 struct string_list
* last_elem
= sub_project_dirs
;
2168 while (last_elem
->next
) last_elem
= last_elem
->next
;
2169 // add string to last element if empty or create new last element and add it to that
2170 if (last_elem
->str
) {
2171 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
2172 last_elem
= last_elem
->next
;
2173 last_elem
->next
= NULL
;
2175 autostring
cwd_as(get_working_dir());
2176 last_elem
->str
= (*p_aflag
) ? mcopystr(sub_proj_effective_work_dir
) : get_relative_dir(sub_proj_effective_work_dir
, (const char*)cwd_as
);
2180 for (int z
= 0; z
< my_argc
; ++z
) {
2182 // central storage, keep in separate container
2183 base_files
.add(my_argv
[z
]); // string was allocated with new
2186 const cstring
tmp(my_argv
[z
]);
2187 if (!files
.has_key(tmp
)){
2188 files
.add(tmp
, my_argv
[z
]);
2195 Free(my_argv
); // free the array; we keep the pointers
2199 else if (success
== TPD_FAILED
) {
2200 ERROR("Failed to process %s", (const char*)abs_projectLocationURI
);
2201 result
= TPD_FAILED
;
2203 // else TPD_SKIPPED, keep quiet
2205 name
= projectLocationURI
= tpdName_loc
= NULL
; // forget all
2207 } // next referenced project
2211 if (get_path_status(output_file
) == PS_DIRECTORY
) {
2212 // points to existing dir; use as-is
2214 else { // we assume it points to a file: not our problem
2219 // (argc - optind) is the number of non-option arguments (assumed to be files)
2220 // given on the command line.
2221 int new_argc
= local_argc
- local_optind
+ files
.size() + base_files
.size();
2222 char ** new_argv
= (char**)Malloc(sizeof(char*) * new_argc
);
2226 // First, copy the filenames gathered from the TPD
2228 // We symlink the files into the working directory
2229 // and pass only the filename to the makefile generator
2230 for (int nf
= files
.size(); n
< nf
; ++n
) {
2231 const char *fn
= files
.get_nth_elem(n
); // relativeURI to the TPD location
2232 autostring
dir_n (get_dir_from_path (fn
));
2233 autostring
file_n(get_file_from_path(fn
));
2234 autostring
rel_n (get_absolute_dir(dir_n
, abs_tpd_dir
, TRUE
));
2235 autostring
abs_n (compose_path_name(rel_n
, file_n
));
2237 if (local_argc
== 0) {
2238 // We are being invoked recursively, for a referenced TPD.
2239 // Do not symlink; just return absolute paths to the files.
2242 // compose with workdir
2243 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
2245 // it's an absolute path, copy verbatim
2246 new_argv
[n
] = mcopystr(fn
); // fn will be destroyed, pass a copy
2249 else { // relative path
2251 // compose with workdir
2252 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
2253 // Do not call file_n.extract() : the composed path will be returned,
2254 // its component will need to be deallocated here.
2257 // compose with tpd dir
2258 new_argv
[n
] = const_cast<char*>(abs_n
.extract());
2262 else { // we are processing the top-level TPD
2265 int fd
= open(abs_n
, O_RDONLY
);
2266 if (fd
>= 0) { // successfully opened
2269 file_n
= compose_path_name(output_file
, file_n
);
2271 //TODO ! compose with output_file
2272 // save into list: add symlink data to the end of list
2273 if (create_symlink_list
) {
2274 // go to last element
2275 struct string2_list
* last_elem
= create_symlink_list
;
2276 while (last_elem
->next
) last_elem
= last_elem
->next
;
2277 // add strings to last element if empty or create new last element and add it to that
2278 if (last_elem
->str1
) {
2279 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2280 last_elem
= last_elem
->next
;
2281 last_elem
->next
= NULL
;
2283 last_elem
->str1
= mcopystr(abs_n
);
2284 last_elem
->str2
= mcopystr(file_n
);
2288 ERROR("%s does not exist", (const char*)abs_n
);
2294 puts((const char *)abs_n
);
2296 autostring
dir_part(get_dir_from_path(abs_n
));
2297 autostring
file_part(get_file_from_path(abs_n
));
2298 autostring
rel_dir_part(get_relative_dir((const char *)dir_part
, file_list_path
? file_list_path
: (const char *)abs_tpd_dir
));
2299 autostring
rel_dir_file_part(compose_path_name((const char *)rel_dir_part
, (const char *)file_part
));
2300 puts((const char *)rel_dir_file_part
);
2303 new_argv
[n
] = const_cast<char *>(file_n
.extract());
2306 // Print the TPD too.
2308 autostring
dir_part(get_dir_from_path(p_tpd_name
));
2309 autostring
file_part(get_file_from_path(p_tpd_name
));
2311 puts((const char *)abs_tpd_name
);
2313 autostring
rel_dir_part(get_relative_dir(dir_part
, file_list_path
? file_list_path
: abs_tpd_dir
));
2314 autostring
rel_dir_file_part(compose_path_name(rel_dir_part
, file_part
));
2315 const char *rel_tpd_name
= (const char *)rel_dir_file_part
;
2320 // base_files from referenced projects
2321 for (size_t bf
= 0, bs
= base_files
.size(); bf
< bs
; ++bf
, ++n
) {
2322 new_argv
[n
] = base_files
[bf
];
2324 base_files
.clear(); // string ownership transfered
2326 // Then, copy the filenames from the command line.
2327 for (int a
= *p_optind
; a
< *p_argc
; ++a
, ++n
) {
2328 // String may be from main's argv; copy to the heap.
2329 new_argv
[n
] = mcopystr((*p_argv
)[a
]);
2332 if (local_argc
> 0) { // it is the outermost call
2333 clear_seen_tpd_files(seen_tpd_files
);
2341 for (size_t i
= 0, e
= files
.size(); i
< e
; ++i
) {
2342 Free(const_cast<char*>(files
.get_nth_elem(i
)));
2346 for (size_t i
= 0, e
= folders
.size(); i
< e
; ++i
) {
2347 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
2352 Free((char*)p_tpd_name
);
2355 excluded_files
.clear();
2356 excluded_folders
.clear();