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_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
637 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
638 struct string_list
* linkerlibs
, struct string_list
* additionalObjects
, struct string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
,
639 boolean
*p_Zflag
, boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
640 struct string2_list
* run_command_list
, map
<cstring
, int>& seen_tpd_files
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
641 const char **search_paths
, size_t n_search_paths
);
643 extern "C" tpd_result
process_tpd(const char *p_tpd_name
, const char *actcfg
,
644 const char *file_list_path
, int *p_argc
, char ***p_argv
,
645 int *p_optind
, char **p_ets_name
, char **p_project_name
,
646 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
647 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
648 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
649 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
650 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
651 struct string_list
* ttcn3_prep_defines
, struct string_list
* ttcn3_prep_undefines
, struct string_list
* prep_includes
,
652 struct string_list
* prep_defines
, struct string_list
* prep_undefines
, boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
,
653 char** cxxcompiler
, char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
,
654 boolean
* p_djflag
, boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
655 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, boolean
* p_Mflag
, boolean
* p_Eflag
, boolean
* p_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
656 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
657 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
, boolean
*p_Zflag
,
658 boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
659 struct string2_list
* run_command_list
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
660 const char **search_paths
, size_t n_search_paths
) {
662 map
<cstring
, int> seen_tpd_files
;
663 char *tpdName
= NULL
;
664 projGenHelper
.setZflag(*p_Zflag
);
665 projGenHelper
.setWflag(prefix_workdir
);
666 projGenHelper
.setHflag(*p_Hflag
);
667 tpd_result success
= process_tpd_internal(p_tpd_name
, tpdName
,
668 actcfg
, file_list_path
, p_argc
, p_argv
, p_optind
, p_ets_name
, p_project_name
,
669 p_gflag
, p_sflag
, p_cflag
, p_aflag
, preprocess
,
670 p_Rflag
, p_lflag
, p_mflag
, p_Pflag
,
671 p_Lflag
, recursive
, force_overwrite
, gen_only_top_level
,
672 output_file
, abs_work_dir_p
, sub_project_dirs
,
673 program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
,
674 ttcn3_prep_defines
, ttcn3_prep_undefines
, prep_includes
, prep_defines
,
675 prep_undefines
, p_csflag
, p_quflag
, p_dsflag
, cxxcompiler
,
676 optlevel
, optflags
, p_dbflag
, p_drflag
, p_dtflag
, p_dxflag
, p_djflag
,
677 p_fxflag
, p_doflag
, p_gfflag
, p_lnflag
, p_isflag
,
678 p_asflag
, p_swflag
, p_Yflag
, p_Mflag
, p_Eflag
, p_diflag
, solspeclibs
, sol8speclibs
,
679 linuxspeclibs
, freebsdspeclibs
, win32speclibs
, ttcn3prep
,
680 linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, Dflag
, p_Zflag
,
681 p_Hflag
, generatorCommandOutput
, target_placement_list
, prefix_workdir
,
682 run_command_list
, seen_tpd_files
, required_configs
, profiled_file_list
,
683 search_paths
, n_search_paths
);
685 if (TPD_FAILED
== success
) exit(EXIT_FAILURE
);
687 if (false == projGenHelper
.sanityCheck()) {
688 fprintf (stderr
, "makefilegen exits\n");
692 projGenHelper
.generateRefProjectWorkingDirsTo(*p_project_name
);
694 for (size_t i
= 0, num
= seen_tpd_files
.size(); i
< num
; ++i
) {
695 const cstring
& key
= seen_tpd_files
.get_nth_key(i
);
696 int *elem
= seen_tpd_files
.get_nth_elem(i
);
700 seen_tpd_files
.clear();
705 // optind is the index of the next element of argv to be processed.
706 // Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
707 // seen already, or TPD_FAILED.
709 // Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
710 // (argv[], ets_name, other_files[], output_file) are allocated on the heap
711 // and need to be freed. On input, these strings point into argv.
712 // process_tpd() may alter these strings; new values will be on the heap.
713 // If process_tpd() preserves the content of such a string (e.g. ets_name),
714 // it must nevertheless make a copy on the heap via mcopystr().
715 static tpd_result
process_tpd_internal(const char *p_tpd_name
, char *tpdName
, const char *actcfg
,
716 const char *file_list_path
, int *p_argc
, char ***p_argv
,
717 int *p_optind
, char **p_ets_name
, char **p_project_name
,
718 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
719 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
720 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
721 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
722 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
723 struct string_list
* ttcn3_prep_defines
, struct string_list
* ttcn3_prep_undefines
, struct string_list
* prep_includes
,
724 struct string_list
* prep_defines
, struct string_list
* prep_undefines
, boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
,
725 char** cxxcompiler
, char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
,
726 boolean
* p_djflag
, boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
727 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, boolean
* p_Mflag
, boolean
* p_Eflag
, boolean
* p_diflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
728 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
729 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
, boolean
*p_Zflag
,
730 boolean
*p_Hflag
, char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
,
731 struct string2_list
* run_command_list
, map
<cstring
, int>& seen_tpd_files
, struct string2_list
* required_configs
, struct string_list
** profiled_file_list
,
732 const char **search_paths
, size_t n_search_paths
)
734 tpd_result result
= TPD_SUCCESS
;
735 // read-only non-pointer aliases
736 //char** const& local_argv = *p_argv;
737 int const& local_argc
= *p_argc
;
738 int const& local_optind
= *p_optind
;
739 *abs_work_dir_p
= NULL
;
741 assert(local_optind
>= 2 // at least '-ttpd_name' must be in the args
742 || local_optind
== 0); // if called for a referenced project
744 assert(local_argc
>= local_optind
);
746 autostring
tpd_dir(get_dir_from_path(p_tpd_name
));
747 autostring
abs_tpd_dir(get_absolute_dir(tpd_dir
, NULL
, FALSE
));
748 boolean free_name
= FALSE
;
750 //Only referenced project, when first try is failed, and when not absolute path
751 if(0 == local_optind
&& p_tpd_name
!= NULL
&& stat(p_tpd_name
, &buf
) && tpdName
!= NULL
) {
752 //Find the first search_path that has the tpd
753 for(size_t i
= 0; i
<n_search_paths
; i
++) {
754 boolean need_slash
= search_paths
[i
][strlen(search_paths
[i
]) - 1] != '/';
755 NOTIFY("Cannot find %s, trying with %s%s%s\n", p_tpd_name
, search_paths
[i
], need_slash
? "/" : "", tpdName
);
757 char * prefixed_file_path
= (char*)Malloc((strlen(search_paths
[i
]) + strlen(tpdName
) + 1 + need_slash
) * sizeof(char));
758 strcpy(prefixed_file_path
, search_paths
[i
]);
760 strcat(prefixed_file_path
, "/");
762 strcat(prefixed_file_path
, tpdName
);
764 tpd_dir
= get_dir_from_path(prefixed_file_path
);
765 abs_tpd_dir
= get_absolute_dir(tpd_dir
, NULL
, FALSE
);
767 if(!stat(prefixed_file_path
, &buf
)){
769 p_tpd_name
= prefixed_file_path
;
771 NOTIFY("TPD with name %s found at %s.", tpdName
, search_paths
[i
]);
774 //tpd not found, continue search
776 Free(prefixed_file_path
);
779 //Error if tpd is not found in either search paths
780 if(NULL
== (const char*)abs_tpd_dir
) {
781 //Only write out the name in the error message (without .tpd)
782 tpdName
[strlen(tpdName
)-4] ='\0';
783 ERROR("Unable to find ReferencedProject with name: %s", (const char*)tpdName
);
788 if (NULL
== (const char*)abs_tpd_dir
) {
789 ERROR("absolute TPD directory could not be retrieved from %s", (const char*)tpd_dir
);
792 autostring
tpd_filename(get_file_from_path(p_tpd_name
));
793 autostring
abs_tpd_name(compose_path_name(abs_tpd_dir
, tpd_filename
));
795 if (seen_tpd_files
.has_key(abs_tpd_name
)) {
796 ++*seen_tpd_files
[abs_tpd_name
];
797 return TPD_SKIPPED
; // nothing to do
800 if (recursive
&& !prefix_workdir
) {
801 // check that this tpd file is not inside a directory of another tpd file
802 for (size_t i
= 0; i
< seen_tpd_files
.size(); ++i
) {
803 const cstring
& other_tpd_name
= seen_tpd_files
.get_nth_key(i
);
804 autostring
other_tpd_dir(get_dir_from_path((const char*)other_tpd_name
));
805 if (strcmp((const char*)abs_tpd_dir
,(const char*)other_tpd_dir
)==0) {
806 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
);
811 // mcopystr makes another copy for the map
812 seen_tpd_files
.add(cstring(mcopystr(abs_tpd_name
)), new int(1));
815 vector
<char> base_files
; // values Malloc'd but we pass them to the caller
817 XmlDoc
doc(xmlParseFile(p_tpd_name
));
819 fprintf(stderr
, "Error: unable to parse file \"%s\"\n", p_tpd_name
);
824 // try schema validation if tpd schema file was found
825 bool tpd_is_valid
= false;
826 const char* ttcn3_dir
= getenv("TTCN3_DIR");
828 size_t ttcn3_dir_len
= strlen(ttcn3_dir
);
829 bool ends_with_slash
= (ttcn3_dir_len
>0) && (ttcn3_dir
[ttcn3_dir_len
- 1]=='/');
830 expstring_t xsd_file_name
= mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir
, ends_with_slash
?"":"/");
831 autostring
xsd_file_name_as(xsd_file_name
);
832 if (get_path_status(xsd_file_name
)==PS_FILE
) {
833 if (validate_tpd(doc
, p_tpd_name
, xsd_file_name
)) {
835 NOTIFY("TPD file `%s' validated successfully with schema file `%s'", p_tpd_name
, xsd_file_name
);
838 ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name
);
841 ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
849 // Key is projectRelativePath, value is relativeURI or rawURI.
850 map
<cstring
, const char> files
; // values Malloc'd
851 map
<cstring
, const char> folders
; // values Malloc'd
852 // NOTE! files and folders must be local variables of process_tpd.
853 // This is because the keys (not the values) are owned by the XmlDoc.
855 map
<cstring
, const char> path_vars
;
857 XPathContext
xpathCtx(xmlXPathNewContext(doc
));
858 if (xpathCtx
== NULL
) {
859 fprintf(stderr
,"Error: unable to create new XPath context\n");
862 // Collect path variables
864 XPathObject
pathsObj(run_xpath(xpathCtx
,
865 "/TITAN_Project_File_Information/PathVariables/PathVariable"));
866 xmlNodeSetPtr nodes
= pathsObj
->nodesetval
;
868 const char *name
= 0, *value
= 0;
869 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
870 // nodes->nodeTab[i]->name === "PathVariable"
871 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
872 if (!strcmp((const char*)attr
->name
, "name")) {
873 name
= (const char*)attr
->children
->content
;
875 else if (!strcmp((const char*)attr
->name
, "value")) {
876 value
= (const char*)attr
->children
->content
;
879 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
883 if (name
&& value
) path_vars
.add(cstring(name
), value
);
884 else ERROR("A PathVariable must have both name and value");
885 } // next PathVariable
890 XPathObject
foldersObj(run_xpath(xpathCtx
,
891 "/TITAN_Project_File_Information/Folders/FolderResource"));
893 xmlNodeSetPtr nodes
= foldersObj
->nodesetval
;
894 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
895 // nodes->nodeTab[i]->name === "FolderResource"
896 const char *uri
= 0, *path
= 0, *raw
= 0;
898 // projectRelativePath is the path as it appears in Project Explorer (illusion)
899 // relativeURI is the actual location, relative to the project root (reality)
900 // rawURI is present if the relative path can not be calculated
902 // Theoretically these attributes could be in any order, loop over them
903 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
904 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
905 path
= (const char*)attr
->children
->content
;
907 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
908 uri
= (const char*)attr
->children
->content
;
910 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
911 raw
= (const char*)attr
->children
->content
;
914 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
919 ERROR("A FolderResource must have a projectRelativePath");
923 if (uri
== NULL
&& raw
== NULL
) {
924 ERROR("A FolderResource must have either relativeURI or rawURI");
927 // relativeURI wins over rawURI
928 folders
.add(cstring(path
), uri
? mcopystr(uri
) : cook(raw
, path_vars
));
929 // TODO uri: cut "file:", complain on anything else
930 } // next FolderResource
933 /////////////////////////////////////////////////////////////////////////////
935 char *projectNameXpath
= mprintf("/TITAN_Project_File_Information/ProjectName/text()");
936 XPathObject
projectNameObj(run_xpath(xpathCtx
, projectNameXpath
));
937 Free(projectNameXpath
);
938 if (projectNameObj
->nodesetval
&& projectNameObj
->nodesetval
->nodeNr
> 0) {
939 *p_project_name
= mcopystr((const char*)projectNameObj
->nodesetval
->nodeTab
[0]->content
);
940 projGenHelper
.addTarget(*p_project_name
);
941 projGenHelper
.setToplevelProjectName(*p_project_name
);
942 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
943 if (projDesc
) projDesc
->setProjectAbsTpdDir((const char*)abs_tpd_dir
);
946 /////////////////////////////////////////////////////////////////////////////
949 actcfg
= get_act_config(required_configs
,*p_project_name
);
951 if (actcfg
== NULL
) {
952 // Find out the active config
953 XPathObject
activeConfig(run_xpath(xpathCtx
,
954 "/TITAN_Project_File_Information/ActiveConfiguration/text()"));
955 if (activeConfig
->nodesetval
&& activeConfig
->nodesetval
->nodeNr
== 1) {
957 actcfg
= (const char*)activeConfig
->nodesetval
->nodeTab
[0]->content
;
961 if (actcfg
== NULL
) {
962 ERROR("Can not find the active build configuration.");
963 for (size_t i
= 0; i
< folders
.size(); ++i
) {
964 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
970 { // check if the active configuration exists
971 expstring_t xpathActCfg
= mprintf(
972 "/TITAN_Project_File_Information/Configurations/"
973 "Configuration[@name='%s']/text()", actcfg
);
974 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfg
));
977 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
979 ERROR("The active build configuration named '%s' does not exist",
981 for (size_t i
= 0; i
< folders
.size(); ++i
) {
982 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
988 // working directory stuff
991 const char* workdirFromTpd
= "bin"; // default value
992 char *workdirXpath
= mprintf(
993 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
994 "/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
996 XPathObject
workdirObj(run_xpath(xpathCtx
, workdirXpath
));
998 if (workdirObj
->nodesetval
&& workdirObj
->nodesetval
->nodeNr
> 0) {
999 workdirFromTpd
= (const char*)workdirObj
->nodesetval
->nodeTab
[0]->content
;
1001 if (prefix_workdir
) { // the working directory is: prjNameStr + "_" + workdirFromTpd
1002 const char* prjNameStr
= "unnamedproject";
1003 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
1004 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1005 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1007 workdir
= mprintf("%s_%s", prjNameStr
, workdirFromTpd
);
1009 workdir
= mcopystr(workdirFromTpd
);
1012 if (!folders
.has_key(workdir
)) {
1013 // Maybe the tpd was saved with the option "No info about work dir"
1014 folders
.add(workdir
, mcopystr(workdir
)); // fake it
1016 const char *real_workdir
= folders
[workdir
]; // This is relative to the location of the tpd file
1017 excluded_folders
.add(real_workdir
); // excluded by convention
1019 autostring proj_abs_workdir
;
1021 autostring abs_workdir
;
1022 // If -D flag was specified then we ignore the workdir
1023 // in the TPD (the current dir is considered the work dir).
1025 bool hasWorkDir
= false;
1026 // if the working directory does not exist create it
1027 autostring
saved_work_dir(get_working_dir());
1028 if (set_working_dir(abs_tpd_dir
)) {
1029 ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir
);
1031 switch (get_path_status(real_workdir
)) {
1033 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
);
1040 if (recursive
|| local_argc
!= 0) { // we only want to create workdir if necessary
1041 fprintf(stderr
, "Working directory `%s' in project `%s' does not exist, trying to create it...\n",
1042 real_workdir
, (const char*)abs_tpd_dir
);
1043 int rv
= mkdir(real_workdir
, 0755);
1044 if (rv
) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno
));
1045 else printf("Working directory created\n");
1051 if (local_argc
==0) { // if not top level
1052 set_working_dir(saved_work_dir
); // restore working directory
1053 } else { // if top level
1054 set_working_dir(real_workdir
); // go into the working dir
1056 if (hasWorkDir
) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
1057 *abs_work_dir_p
= get_absolute_dir(real_workdir
, abs_tpd_dir
, TRUE
);
1058 abs_workdir
= (mcopystr(*abs_work_dir_p
));
1059 proj_abs_workdir
= mcopystr(*abs_work_dir_p
);
1063 if (Dflag
) { // the path to subproject working dir is needed to find the linkerlibsearchpath
1064 proj_abs_workdir
= compose_path_name(abs_tpd_dir
, real_workdir
);
1067 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1069 projDesc
->setProjectAbsWorkingDir((const char*)proj_abs_workdir
);
1070 projDesc
->setProjectWorkingDir(real_workdir
);
1071 projDesc
->setTPDFileName(p_tpd_name
);
1074 /////////////////////////////////////////////////////////////////////////////
1076 // Gather the excluded folders in the active config
1078 expstring_t xpathActCfgPaths
= mprintf(
1079 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1080 "/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
1081 // This was the selection criterium, we need to go up and down for the actual information
1082 "/parent::*/parent::*/FolderPath/text()",
1084 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
1085 Free(xpathActCfgPaths
);
1087 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
1088 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1090 excluded_folders
.add((const char*)nodes
->nodeTab
[i
]->content
);
1094 // Gather individual excluded files in the active config
1096 expstring_t xpathActCfgPaths
= mprintf(
1097 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1098 "/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
1099 "/parent::*/parent::*/FilePath/text()",
1101 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
1102 Free(xpathActCfgPaths
);
1104 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
1105 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1106 xmlNodePtr curnode
= nodes
->nodeTab
[i
];
1107 cstring
aa((const char*)curnode
->content
);
1108 if (!excluded_files
.has_key(aa
)) {
1109 excluded_files
.add(aa
, *p_project_name
);
1111 WARNING("Multiple exclusion of file %s", (const char*)curnode
->content
);
1116 // Collect files; filter out excluded ones
1118 XPathObject
filesObj(run_xpath(xpathCtx
,
1119 "TITAN_Project_File_Information/Files/FileResource"));
1121 xmlNodeSetPtr nodes
= filesObj
->nodesetval
;
1122 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1123 // nodes->nodeTab[i]->name === "FileResource"
1124 const char *uri
= 0, *path
= 0, *raw
= 0;
1126 // projectRelativePath is the path as it appears in Project Explorer (illusion)
1127 // relativeURI is the actual location, relative to the project root (reality)
1128 // rawURI is present if the relative path can not be calculated
1130 // Theoretically these attributes could be in any order, loop over them
1131 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
1132 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
1133 path
= (const char*)attr
->children
->content
;
1135 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
1136 uri
= (const char*)attr
->children
->content
;
1138 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
1139 raw
= (const char*)attr
->children
->content
;
1142 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
1147 ERROR("A FileResource must have a projectRelativePath");
1151 if (uri
== NULL
&& raw
== NULL
) {
1152 ERROR("A FileResource must have either relativeURI or rawURI");
1156 cstring
cpath(path
);
1157 if (!is_excluded_file(cpath
, *p_project_name
) && !is_excluded_folder(path
)) {
1158 // relativeURI wins over rawURI
1159 char *ruri
= uri
? mcopystr(uri
) : cook(raw
, path_vars
);
1160 if (files
.has_key(cpath
)) {
1161 ERROR("A FileResource %s must be unique!", (const char*)cpath
);
1165 const char* file_path
= ruri
;
1166 expstring_t rel_file_dir
= get_dir_from_path(file_path
);
1167 expstring_t file_name
= get_file_from_path(file_path
);
1168 expstring_t abs_dir_path
= get_absolute_dir(rel_file_dir
, abs_tpd_dir
, TRUE
);
1169 expstring_t abs_file_name
= compose_path_name(abs_dir_path
, file_name
);
1170 if (abs_file_name
!= NULL
) {
1171 if (get_path_status(abs_file_name
) == PS_FILE
) {
1172 FILE *fp
= fopen(abs_file_name
, "r");
1174 char* ttcn3_module_name
;
1175 if (is_ttcn3_module(abs_file_name
, fp
, &ttcn3_module_name
)) {
1176 projGenHelper
.addTtcn3ModuleToProject(*p_project_name
, ttcn3_module_name
);
1178 Free(ttcn3_module_name
);
1179 char* asn1_module_name
;
1180 if (is_asn1_module(abs_file_name
, fp
, &asn1_module_name
)) {
1181 projGenHelper
.addAsn1ModuleToProject(*p_project_name
, asn1_module_name
);
1183 Free(asn1_module_name
);
1184 if (projGenHelper
.isCPPSourceFile(file_name
)) {
1185 projGenHelper
.addUserSourceToProject(*p_project_name
, file_name
);
1187 if (projGenHelper
.isCPPHeaderFile(file_name
)) {
1188 projGenHelper
.addUserHeaderToProject(*p_project_name
, file_name
);
1190 if (projGenHelper
.isTtcnPPFile(file_name
)) {
1191 projGenHelper
.addTtcnPPToProject(*p_project_name
, file_name
);
1197 ERROR("%s does not exist", abs_file_name
);
1200 if(abs_dir_path
!= NULL
&& !drop
){
1201 files
.add(cpath
, ruri
); // relativeURI to the TPD location
1204 result
= TPD_FAILED
;
1206 { // set the *preprocess value if .ttcnpp file was found
1207 const size_t ttcnpp_extension_len
= 7; // ".ttcnpp"
1208 const size_t ruri_len
= strlen(ruri
);
1209 if ( ruri_len
>ttcnpp_extension_len
&& strcmp(ruri
+(ruri_len
-ttcnpp_extension_len
),".ttcnpp")==0 ) {
1216 Free(abs_file_name
);
1219 } // next FileResource
1223 xsdbool2boolean(xpathCtx
, actcfg
, "useAbsolutePath", p_aflag
);
1224 xsdbool2boolean(xpathCtx
, actcfg
, "GNUMake", p_gflag
);
1225 if (*p_Zflag
) *p_lflag
= FALSE
;
1226 xsdbool2boolean(xpathCtx
, actcfg
, "dynamicLinking", p_lflag
);
1227 xsdbool2boolean(xpathCtx
, actcfg
, "functiontestRuntime", p_Rflag
);
1228 xsdbool2boolean(xpathCtx
, actcfg
, "singleMode", p_sflag
);
1229 xsdbool2boolean(xpathCtx
, actcfg
, "codeSplitting", p_csflag
);
1230 xsdbool2boolean(xpathCtx
, actcfg
, "quietly", p_quflag
);
1231 xsdbool2boolean(xpathCtx
, actcfg
, "disableSubtypeChecking", p_dsflag
);
1232 xsdbool2boolean(xpathCtx
, actcfg
, "disableBER", p_dbflag
);
1233 xsdbool2boolean(xpathCtx
, actcfg
, "disableRAW", p_drflag
);
1234 xsdbool2boolean(xpathCtx
, actcfg
, "disableTEXT", p_dtflag
);
1235 xsdbool2boolean(xpathCtx
, actcfg
, "disableXER", p_dxflag
);
1236 xsdbool2boolean(xpathCtx
, actcfg
, "disableJSON", p_djflag
);
1237 xsdbool2boolean(xpathCtx
, actcfg
, "forceXERinASN.1", p_fxflag
);
1238 xsdbool2boolean(xpathCtx
, actcfg
, "defaultasOmit", p_doflag
);
1239 xsdbool2boolean(xpathCtx
, actcfg
, "gccMessageFormat", p_gfflag
);
1240 xsdbool2boolean(xpathCtx
, actcfg
, "lineNumbersOnlyInMessages", p_lnflag
);
1241 xsdbool2boolean(xpathCtx
, actcfg
, "includeSourceInfo", p_isflag
);
1242 xsdbool2boolean(xpathCtx
, actcfg
, "addSourceLineInfo", p_asflag
);
1243 xsdbool2boolean(xpathCtx
, actcfg
, "suppressWarnings", p_swflag
);
1244 xsdbool2boolean(xpathCtx
, actcfg
, "outParamBoundness", p_Yflag
); //not documented, obsolete
1245 xsdbool2boolean(xpathCtx
, actcfg
, "forceOldFuncOutParHandling", p_Yflag
);
1246 xsdbool2boolean(xpathCtx
, actcfg
, "omitInValueList", p_Mflag
);
1247 xsdbool2boolean(xpathCtx
, actcfg
, "warningsForBadVariants", p_Eflag
);
1248 xsdbool2boolean(xpathCtx
, actcfg
, "disablePredefinedExternalFolder", p_diflag
);
1250 projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1251 if (projDesc
) projDesc
->setLinkingStrategy(*p_lflag
);
1253 // Extract the "incremental dependencies" option
1255 boolean incremental_deps
= TRUE
;
1256 xsdbool2boolean(xpathCtx
, actcfg
, "incrementalDependencyRefresh", &incremental_deps
);
1258 // For makefilegen, "Use GNU make" implies incremental deps by default,
1259 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
1260 // For Eclipse, incremental deps must be explicitly specified,
1261 // even if GNU make is being used.
1263 if (incremental_deps
) {
1265 WARNING("Incremental dependency ordered but it requires gnu make");
1270 // GNU make but no incremental deps
1276 // Extract the default target option
1277 // if it is not defined as a command line argument
1279 expstring_t defTargetXpath
= mprintf(
1280 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1281 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
1283 XPathObject
defTargetObj(run_xpath(xpathCtx
, defTargetXpath
));
1284 Free(defTargetXpath
);
1285 if (defTargetObj
->nodesetval
&& defTargetObj
->nodesetval
->nodeNr
> 0) {
1286 const char* content
= (const char*)defTargetObj
->nodesetval
->nodeTab
[0]->content
;
1287 if (!strcmp(content
, "library")) {
1289 } else if (!strcmp(content
, "executable")) {
1292 ERROR("Unknown default target: '%s'."
1293 " The available targets are: 'executable', 'library'", content
);
1296 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1297 if (projDesc
) projDesc
->setLibrary(*p_Lflag
);
1300 // Executable name (don't care unless top-level invocation)
1301 if (local_argc
!= 0)
1303 char *exeXpath
= mprintf(
1304 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1305 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
1307 XPathObject
exeObj(run_xpath(xpathCtx
, exeXpath
));
1309 if (exeObj
->nodesetval
&& exeObj
->nodesetval
->nodeNr
> 0) {
1310 const char* target_executable
= (const char*)exeObj
->nodesetval
->nodeTab
[0]->content
;
1311 autostring
target_exe_dir(get_dir_from_path(target_executable
));
1312 autostring
target_exe_file(get_file_from_path(target_executable
));
1313 if (target_exe_dir
!=NULL
) { // if it's not only a file name
1314 if (get_path_status(target_exe_dir
)==PS_NONEXISTENT
) {
1315 if (strcmp(real_workdir
,target_exe_dir
)!=0) {
1316 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
);
1318 target_executable
= target_exe_file
;
1321 if (!*p_ets_name
) { // Command line will win
1322 *p_ets_name
= mcopystr(target_executable
);
1327 // create an xml element for the currently processed project
1329 const char* prjNameStr
= "???";
1330 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
1331 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1332 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1334 autostring
tpd_rel_dir(get_relative_dir(tpd_dir
, NULL
));
1335 autostring
tpd_rel_path(compose_path_name(tpd_rel_dir
, (const char*)tpd_filename
));
1336 fprintf(prj_graph_fp
, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr
, (const char*)tpd_rel_path
);
1337 XPathObject
subprojects(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
1338 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
1339 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1340 const char* refd_name
= "???";
1341 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1342 refd_name
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1344 fprintf(prj_graph_fp
, "<reference name=\"%s\"/>\n", refd_name
);
1346 fprintf(prj_graph_fp
, "</project>\n");
1349 // Tpd part of the MakefileSettings
1351 //TTCN3preprocessorIncludes
1352 char *preincludeXpath
= mprintf(
1353 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1354 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
1356 XPathObject
preincludeObj(run_xpath(xpathCtx
, preincludeXpath
));
1357 Free(preincludeXpath
);
1359 xmlNodeSetPtr nodes
= preincludeObj
->nodesetval
;
1361 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1362 char* content
= (char*)preincludeObj
->nodesetval
->nodeTab
[i
]->content
;
1364 // add includes to the end of list
1365 if (ttcn3_prep_includes
) {
1366 // go to last element
1367 struct string_list
* last_elem
= ttcn3_prep_includes
;
1368 while (last_elem
->next
) last_elem
= last_elem
->next
;
1369 // add string to last element if empty or create new last element and add it to that
1370 if (last_elem
->str
) {
1371 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1372 last_elem
= last_elem
->next
;
1373 last_elem
->next
= NULL
;
1375 replacechar(&content
);
1376 last_elem
->str
= content
;
1381 //TTCN3preprocessorDefines
1382 char *ttcn3predefinesXpath
= mprintf(
1383 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1384 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
1386 XPathObject
ttcn3predefinesObj(run_xpath(xpathCtx
, ttcn3predefinesXpath
));
1387 Free(ttcn3predefinesXpath
);
1389 xmlNodeSetPtr nodes
= ttcn3predefinesObj
->nodesetval
;
1391 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1392 const char* content
= (const char*)ttcn3predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1394 // add includes to the end of list
1395 if (ttcn3_prep_defines
) {
1396 // go to last element
1397 struct string_list
* last_elem
= ttcn3_prep_defines
;
1398 while (last_elem
->next
) last_elem
= last_elem
->next
;
1399 // add string to last element if empty or create new last element and add it to that
1400 if (last_elem
->str
) {
1401 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1402 last_elem
= last_elem
->next
;
1403 last_elem
->next
= NULL
;
1405 last_elem
->str
= mcopystr(content
);
1410 //TTCN3preprocessorUnDefines
1411 char *ttcn3preUndefinesXpath
= mprintf(
1412 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1413 "/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()",
1415 XPathObject
ttcn3preUndefinesObj(run_xpath(xpathCtx
, ttcn3preUndefinesXpath
));
1416 Free(ttcn3preUndefinesXpath
);
1418 xmlNodeSetPtr nodes
= ttcn3preUndefinesObj
->nodesetval
;
1420 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1421 const char* content
= (const char*)ttcn3preUndefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1423 // add includes to the end of list
1424 if (ttcn3_prep_undefines
) {
1425 // go to last element
1426 struct string_list
* last_elem
= ttcn3_prep_undefines
;
1427 while (last_elem
->next
) last_elem
= last_elem
->next
;
1428 // add string to last element if empty or create new last element and add it to that
1429 if (last_elem
->str
) {
1430 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1431 last_elem
= last_elem
->next
;
1432 last_elem
->next
= NULL
;
1434 last_elem
->str
= mcopystr(content
);
1440 //preprocessorIncludes
1441 char *preincludesXpath
= mprintf(
1442 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1443 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
1445 XPathObject
preincludesObj(run_xpath(xpathCtx
, preincludesXpath
));
1446 Free(preincludesXpath
);
1448 xmlNodeSetPtr nodes
= preincludesObj
->nodesetval
;
1450 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1451 char* content
= (char*)preincludesObj
->nodesetval
->nodeTab
[i
]->content
;
1453 // add includes to the end of list
1454 if (prep_includes
) {
1455 // go to last element
1456 struct string_list
* last_elem
= prep_includes
;
1457 while (last_elem
->next
) last_elem
= last_elem
->next
;
1458 // add string to last element if empty or create new last element and add it to that
1459 if (last_elem
->str
) {
1460 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1461 last_elem
= last_elem
->next
;
1462 last_elem
->next
= NULL
;
1464 replacechar(&content
);
1465 last_elem
->str
= content
;
1470 //preprocessorDefines
1471 char *predefinesXpath
= mprintf(
1472 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1473 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
1475 XPathObject
predefinesObj(run_xpath(xpathCtx
, predefinesXpath
));
1476 Free(predefinesXpath
);
1478 xmlNodeSetPtr nodes
= predefinesObj
->nodesetval
;
1480 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1481 const char* content
= (const char*)predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1483 // add includes to the end of list
1485 // go to last element
1486 struct string_list
* last_elem
= prep_defines
;
1487 while (last_elem
->next
) last_elem
= last_elem
->next
;
1488 // add string to last element if empty or create new last element and add it to that
1489 if (last_elem
->str
) {
1490 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1491 last_elem
= last_elem
->next
;
1492 last_elem
->next
= NULL
;
1494 last_elem
->str
= mcopystr(content
);
1499 //preprocessorUnDefines
1500 char *preUndefinesXpath
= mprintf(
1501 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1502 "/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()",
1504 XPathObject
preUndefinesObj(run_xpath(xpathCtx
, preUndefinesXpath
));
1505 Free(preUndefinesXpath
);
1507 xmlNodeSetPtr nodes
= preUndefinesObj
->nodesetval
;
1509 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1510 const char* content
= (const char*)preUndefinesObj
->nodesetval
->nodeTab
[i
]->content
;
1512 // add includes to the end of list
1513 if (prep_undefines
) {
1514 // go to last element
1515 struct string_list
* last_elem
= prep_undefines
;
1516 while (last_elem
->next
) last_elem
= last_elem
->next
;
1517 // add string to last element if empty or create new last element and add it to that
1518 if (last_elem
->str
) {
1519 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1520 last_elem
= last_elem
->next
;
1521 last_elem
->next
= NULL
;
1523 last_elem
->str
= mcopystr(content
);
1528 char *cxxCompilerXpath
= mprintf(
1529 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1530 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1532 XPathObject
cxxCompilerObj(run_xpath(xpathCtx
, cxxCompilerXpath
));
1533 Free(cxxCompilerXpath
);
1534 xmlNodeSetPtr nodes
= cxxCompilerObj
->nodesetval
;
1536 *cxxcompiler
= mcopystr((const char*)cxxCompilerObj
->nodesetval
->nodeTab
[0]->content
);
1540 char *optLevelXpath
= mprintf(
1541 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1542 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1544 XPathObject
optLevelObj(run_xpath(xpathCtx
, optLevelXpath
));
1545 Free(optLevelXpath
);
1546 xmlNodeSetPtr nodes
= optLevelObj
->nodesetval
;
1548 *optlevel
= mcopystr((const char*)optLevelObj
->nodesetval
->nodeTab
[0]->content
);
1552 char *optFlagsXpath
= mprintf(
1553 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1554 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1556 XPathObject
optFlagsObj(run_xpath(xpathCtx
, optFlagsXpath
));
1557 Free(optFlagsXpath
);
1558 xmlNodeSetPtr nodes
= optFlagsObj
->nodesetval
;
1560 *optflags
= mcopystr((const char*)optFlagsObj
->nodesetval
->nodeTab
[0]->content
);
1564 //SolarisSpecificLibraries
1565 char *solspeclibXpath
= mprintf(
1566 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1567 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1569 XPathObject
solspeclibObj(run_xpath(xpathCtx
, solspeclibXpath
));
1570 Free(solspeclibXpath
);
1572 xmlNodeSetPtr nodes
= solspeclibObj
->nodesetval
;
1574 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1575 char* content
= (char*)solspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1577 // add includes to the end of list
1579 // go to last element
1580 struct string_list
* last_elem
=solspeclibs
;
1581 while (last_elem
->next
) last_elem
= last_elem
->next
;
1582 // add string to last element if empty or create new last element and add it to that
1583 if (last_elem
->str
) {
1584 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1585 last_elem
= last_elem
->next
;
1586 last_elem
->next
= NULL
;
1588 replacechar(&content
);
1589 last_elem
->str
= content
;
1594 //Solaris8SpecificLibraries
1595 char *sol8speclibXpath
= mprintf(
1596 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1597 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1599 XPathObject
sol8speclibObj(run_xpath(xpathCtx
, sol8speclibXpath
));
1600 Free(sol8speclibXpath
);
1602 xmlNodeSetPtr nodes
= sol8speclibObj
->nodesetval
;
1604 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1605 char* content
= (char*)sol8speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1607 // add includes to the end of list
1609 // go to last element
1610 struct string_list
* last_elem
= sol8speclibs
;
1611 while (last_elem
->next
) last_elem
= last_elem
->next
;
1612 // add string to last element if empty or create new last element and add it to that
1613 if (last_elem
->str
) {
1614 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1615 last_elem
= last_elem
->next
;
1616 last_elem
->next
= NULL
;
1618 replacechar(&content
);
1619 last_elem
->str
= content
;
1624 //LinuxSpecificLibraries
1625 char *linuxspeclibXpath
= mprintf(
1626 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1627 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1629 XPathObject
linuxspeclibObj(run_xpath(xpathCtx
, linuxspeclibXpath
));
1630 Free(linuxspeclibXpath
);
1632 xmlNodeSetPtr nodes
= linuxspeclibObj
->nodesetval
;
1634 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1635 char* content
= (char*)linuxspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1637 // add includes to the end of list
1638 if (linuxspeclibs
) {
1639 // go to last element
1640 struct string_list
* last_elem
= linuxspeclibs
;
1641 while (last_elem
->next
) last_elem
= last_elem
->next
;
1642 // add string to last element if empty or create new last element and add it to that
1643 if (last_elem
->str
) {
1644 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1645 last_elem
= last_elem
->next
;
1646 last_elem
->next
= NULL
;
1648 replacechar(&content
);
1649 last_elem
->str
= content
;
1654 //FreeBSDSpecificLibraries
1655 char *freebsdspeclibXpath
= mprintf(
1656 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1657 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1659 XPathObject
freebsdspeclibObj(run_xpath(xpathCtx
, freebsdspeclibXpath
));
1660 Free(freebsdspeclibXpath
);
1662 xmlNodeSetPtr nodes
= freebsdspeclibObj
->nodesetval
;
1664 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1665 char* content
= (char*)freebsdspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1667 // add includes to the end of list
1668 if (freebsdspeclibs
) {
1669 // go to last element
1670 struct string_list
* last_elem
= freebsdspeclibs
;
1671 while (last_elem
->next
) last_elem
= last_elem
->next
;
1672 // add string to last element if empty or create new last element and add it to that
1673 if (last_elem
->str
) {
1674 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1675 last_elem
= last_elem
->next
;
1676 last_elem
->next
= NULL
;
1678 replacechar(&content
);
1679 last_elem
->str
= content
;
1684 //Win32SpecificLibraries
1685 char *win32speclibXpath
= mprintf(
1686 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1687 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1689 XPathObject
win32speclibObj(run_xpath(xpathCtx
, win32speclibXpath
));
1690 Free(win32speclibXpath
);
1692 xmlNodeSetPtr nodes
= win32speclibObj
->nodesetval
;
1694 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1695 char* content
= (char*)win32speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1697 // add includes to the end of list
1698 if (win32speclibs
) {
1699 // go to last element
1700 struct string_list
* last_elem
= win32speclibs
;
1701 while (last_elem
->next
) last_elem
= last_elem
->next
;
1702 // add string to last element if empty or create new last element and add it to that
1703 if (last_elem
->str
) {
1704 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1705 last_elem
= last_elem
->next
;
1706 last_elem
->next
= NULL
;
1708 replacechar(&content
);
1709 last_elem
->str
= content
;
1716 char *ttcn3preproc
= mprintf(
1717 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1718 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1720 XPathObject
ttcn3preprocObj(run_xpath(xpathCtx
, ttcn3preproc
));
1722 xmlNodeSetPtr nodes
= ttcn3preprocObj
->nodesetval
;
1724 *ttcn3prep
= mcopystr((const char*)ttcn3preprocObj
->nodesetval
->nodeTab
[0]->content
);
1728 // additionalObjects
1729 char *additionalObjectsXpath
= mprintf(
1730 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1731 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1733 XPathObject
additionalObjectsObj(run_xpath(xpathCtx
, additionalObjectsXpath
));
1734 Free(additionalObjectsXpath
);
1736 xmlNodeSetPtr nodes
= additionalObjectsObj
->nodesetval
;
1738 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1739 char* content
= (char*)additionalObjectsObj
->nodesetval
->nodeTab
[i
]->content
;
1741 // add to the end of list
1742 if (additionalObjects
) {
1743 // go to last element
1744 struct string_list
* last_elem
= additionalObjects
;
1745 while (last_elem
->next
) last_elem
= last_elem
->next
;
1746 // add string to last element if empty or create new last element and add it to that
1747 if (last_elem
->str
) {
1748 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1749 last_elem
= last_elem
->next
;
1750 last_elem
->next
= NULL
;
1752 replacechar(&content
);
1753 last_elem
->str
= content
;
1758 //The project name needed the hierarchical projects
1759 char* prjNameStr
= 0;
1760 char *prjNameStrXpath
= mprintf("/TITAN_Project_File_Information/ProjectName/text()");
1761 XPathObject
prjName(run_xpath(xpathCtx
, prjNameStrXpath
));
1762 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
1763 prjNameStr
= (char*)prjName
->nodesetval
->nodeTab
[0]->content
;
1765 Free(prjNameStrXpath
);
1766 append_to_library_list (prjNameStr
, xpathCtx
, actcfg
);
1769 char *linkerlibsXpath
= mprintf(
1770 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1771 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1773 XPathObject
linkerlibsObj(run_xpath(xpathCtx
, linkerlibsXpath
));
1774 Free(linkerlibsXpath
);
1776 xmlNodeSetPtr nodes
= linkerlibsObj
->nodesetval
;
1778 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1779 char* content
= (char*)linkerlibsObj
->nodesetval
->nodeTab
[i
]->content
;
1781 // add includes to the end of list
1783 // go to last element
1784 struct string_list
* last_elem
= linkerlibs
;
1785 while (last_elem
->next
) last_elem
= last_elem
->next
;
1786 // add string to last element if empty or create new last element and add it to that
1787 if (last_elem
->str
) {
1788 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1789 last_elem
= last_elem
->next
;
1790 last_elem
->next
= NULL
;
1792 replacechar(&content
);
1793 last_elem
->str
= content
;
1795 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1796 if (projDesc
) projDesc
->addToLinkerLibs(last_elem
->str
);
1801 //linkerLibrarySearchPath
1802 char *linkerlibsearchXpath
= mprintf(
1803 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1804 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1806 XPathObject
linkerlibsearchObj(run_xpath(xpathCtx
, linkerlibsearchXpath
));
1807 Free(linkerlibsearchXpath
);
1809 xmlNodeSetPtr nodes
= linkerlibsearchObj
->nodesetval
;
1811 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1812 char* content
= (char*)linkerlibsearchObj
->nodesetval
->nodeTab
[i
]->content
;
1814 // add includes to the end of list
1815 if (linkerlibsearchp
) {
1816 // go to last element
1817 struct string_list
* last_elem
= linkerlibsearchp
;
1818 while (last_elem
->next
) last_elem
= last_elem
->next
;
1819 // add string to last element if empty or create new last element and add it to that
1820 if (last_elem
->str
) {
1821 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1822 last_elem
= last_elem
->next
;
1823 last_elem
->next
= NULL
;
1825 replacechar(&content
);
1826 last_elem
->str
= content
;
1828 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
1829 if (projDesc
) projDesc
->addToLibSearchPaths(last_elem
->str
);
1834 if (generatorCommandOutput
&& local_argc
!= 0) { // only in case of top-level invocation
1835 char* generatorCommandXpath
= mprintf(
1836 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1837 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1839 XPathObject
generatorCommandObj(run_xpath(xpathCtx
, generatorCommandXpath
));
1840 Free(generatorCommandXpath
);
1841 autostring generatorCommand
;
1842 if (generatorCommandObj
->nodesetval
&& generatorCommandObj
->nodesetval
->nodeNr
> 0) {
1843 generatorCommand
= mcopystr((const char*)generatorCommandObj
->nodesetval
->nodeTab
[0]->content
);
1844 // run the command and capture the output
1845 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand
, (const char*)abs_tpd_name
);
1846 FILE* gc_fp
= popen(generatorCommand
, "r");
1848 ERROR("Could not execute command `%s'", (const char*)generatorCommand
);
1851 while (fgets(buff
, sizeof(buff
), gc_fp
)!=NULL
) {
1852 *generatorCommandOutput
= mputstr(*generatorCommandOutput
, buff
);
1859 if (target_placement_list
&& local_argc
!= 0) { // only in case of top-level invocation
1860 char* targetPlacementXpath
= mprintf(
1861 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1862 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1864 XPathObject
targetPlacementObj(run_xpath(xpathCtx
, targetPlacementXpath
));
1865 Free(targetPlacementXpath
);
1866 xmlNodeSetPtr nodes
= targetPlacementObj
->nodesetval
;
1867 const char* targetName
= NULL
;
1868 const char* targetPlacement
= NULL
;
1869 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1870 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1871 targetName
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1873 else if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
,"placement")) {
1874 targetPlacement
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1876 if (targetName
&& targetPlacement
) { // collected both
1877 if (target_placement_list
) {
1878 // go to last element
1879 struct string2_list
* last_elem
= target_placement_list
;
1880 while (last_elem
->next
) last_elem
= last_elem
->next
;
1881 // add strings to last element if empty or create new last element and add it to that
1882 if (last_elem
->str1
) {
1883 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
1884 last_elem
= last_elem
->next
;
1885 last_elem
->next
= NULL
;
1887 last_elem
->str1
= mcopystr(targetName
);
1888 last_elem
->str2
= mcopystr(targetPlacement
);
1890 targetName
= targetPlacement
= NULL
; // forget both
1896 // profiler file name
1897 char* profilerXpath
= mprintf(
1898 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1899 "/ProjectProperties/MakefileSettings/profiledFileList", actcfg
);
1900 XPathObject
profiledFilesNameObj(run_xpath(xpathCtx
, profilerXpath
));
1901 Free(profilerXpath
);
1902 xmlNodeSetPtr nodes
= profiledFilesNameObj
->nodesetval
;
1903 if (nodes
&& nodes
->nodeNr
> 0) {
1904 const char *uri
= 0, *path
= 0, *raw
= 0;
1905 for (xmlAttrPtr attr
= nodes
->nodeTab
[0]->properties
; attr
; attr
= attr
->next
) {
1906 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
1907 path
= (const char*)attr
->children
->content
;
1909 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
1910 uri
= (const char*)attr
->children
->content
;
1912 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
1913 raw
= (const char*)attr
->children
->content
;
1916 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[0]->name
);
1921 ERROR("A profiledFileList must have a projectRelativePath");
1924 if (uri
== NULL
&& raw
== NULL
) {
1925 ERROR("A profiledFileList must have either relativeURI or rawURI");
1928 cstring
cpath(path
);
1929 if (files
.has_key(cpath
)) {
1930 ERROR("profiledFileLists and FileResources must be unique!");
1933 // add the file to the end of the list
1934 struct string_list
* new_item
= NULL
;
1935 if (*profiled_file_list
== NULL
) {
1936 *profiled_file_list
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1937 new_item
= *profiled_file_list
;
1940 new_item
= *profiled_file_list
;
1941 while(new_item
->next
!= NULL
) {
1942 new_item
= new_item
->next
;
1944 new_item
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1945 new_item
= new_item
->next
;
1947 new_item
->str
= mcopystr(path
);
1948 new_item
->next
= NULL
;
1950 // add the file to the map of files to be copied to the working directory
1951 char *ruri
= uri
? mcopystr(uri
) : cook(raw
, path_vars
);
1952 files
.add(cpath
, ruri
);
1959 // collect the required configurations
1961 if (required_configs
) {
1962 char* cfgReqsXpath(mprintf(
1963 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1964 "/ProjectProperties/ConfigurationRequirements/configurationRequirement",
1966 XPathObject
reqcfgObjects(run_xpath(xpathCtx
, cfgReqsXpath
));
1967 Free (cfgReqsXpath
);
1968 xmlNodeSetPtr configs
= reqcfgObjects
->nodesetval
;
1969 if (configs
) for (int i
= 0; i
< configs
->nodeNr
; ++i
) {
1970 xmlNodePtr curNodePtr
= configs
->nodeTab
[i
]->children
;
1971 const char* projectName
= NULL
;
1972 const char* reqConfig
= NULL
;
1974 if (!strcmp((const char*)curNodePtr
->name
, "projectName")) {
1975 projectName
= (const char*)curNodePtr
->children
->content
;
1977 if (!strcmp((const char*)curNodePtr
->name
, "rerquiredConfiguration") || // backward compatibility
1978 !strcmp((const char*)curNodePtr
->name
, "requiredConfiguration")) {
1979 reqConfig
= (const char*)curNodePtr
->children
->content
;
1981 curNodePtr
= curNodePtr
->next
;
1983 struct string2_list
* last_elem
= required_configs
;
1984 bool duplicate
= false;
1985 while (last_elem
->next
) {
1986 if (!strcmp(last_elem
->str1
, projectName
) && !strcmp(last_elem
->str2
, reqConfig
)) {
1989 else if (!strcmp(last_elem
->str1
, projectName
) && strcmp(last_elem
->str2
, reqConfig
)) {
1990 ERROR("Required configuration is inconsistent : Project '%s' cannot have 2 "
1991 "different configuration '%s' '%s'",
1992 last_elem
->str1
, last_elem
->str2
, reqConfig
);
1993 result
= TPD_FAILED
;
1995 last_elem
= last_elem
->next
;
1997 // add string to last element if empty or create new last element and add it to that
1998 if (last_elem
->str1
&& !duplicate
) {
1999 if (strcmp(last_elem
->str1
, projectName
) || strcmp(last_elem
->str2
, reqConfig
)) {
2000 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2001 last_elem
= last_elem
->next
;
2002 last_elem
->next
= NULL
;
2009 last_elem
->str1
= mcopystr(projectName
);
2010 last_elem
->str2
= mcopystr(reqConfig
);
2016 // Referenced projects
2018 XPathObject
subprojects(run_xpath(xpathCtx
,
2019 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject"));
2020 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
2021 //Go through ReferencedProjects
2022 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
2023 const char *name
= NULL
, *projectLocationURI
= NULL
;
2024 char *tpdName_loc
= NULL
;
2025 // FIXME: this assumes every ReferencedProject has name and URI.
2026 // This is not necessarily so if the referenced project was closed
2027 // when the project was exported to TPD.
2028 // Luckily, the name from the closed project will be overwritten
2029 // by the name from the next ReferencedProject. However, if some pervert
2030 // changes the next ReferencedProject to have the projectLocationURI
2031 // as the first attribute, it will be joined to the name
2032 // of the previous, closed, ReferencedProject.
2034 //Go through attributes
2035 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
2036 if (!strcmp((const char*)attr
->name
, "name")) {
2037 name
= (const char*)attr
->children
->content
;
2039 else if (!strcmp((const char*)attr
->name
,"projectLocationURI")) {
2040 projectLocationURI
= (const char*)attr
->children
->content
;
2042 else if (!strcmp((const char*)attr
->name
, "tpdName")) {
2044 tpdName_loc
= mcopystr((char*)attr
->children
->content
);
2047 //We don't want to orerride an absolute location with -I, tpdName remains NULL
2048 boolean not_abs_path
= projectLocationURI
&&
2049 #if defined WIN32 && defined MINGW
2050 /* On native Windows the absolute path name shall begin with
2051 * a drive letter, colon and backslash */
2052 (((projectLocationURI
[0] < 'A' || projectLocationURI
[0] > 'Z') &&
2053 (projectLocationURI
[0] < 'a' || projectLocationURI
[0] > 'z')) ||
2054 projectLocationURI
[1] != ':' || projectLocationURI
[2] != '\\');
2056 /* On UNIX-like systems the absolute path name shall begin with
2058 projectLocationURI
[0] != '/';
2060 if (!tpdName_loc
&& not_abs_path
) {
2061 //Allocate memory: +5 because .tpd + closing 0
2062 tpdName_loc
= (char*)Malloc((strlen(name
) + 5) * sizeof(char));
2063 //Default name: name + .tpd
2064 strcpy(tpdName_loc
, name
);
2065 strcat(tpdName_loc
, ".tpd");
2066 }else if (!not_abs_path
) {
2071 if (name
&& projectLocationURI
) { // collected both
2072 // see if there is a specified configuration for the project
2074 ProjectDescriptor
* projDesc
= projGenHelper
.getTargetOfProject(*p_project_name
);
2075 if (projDesc
) projDesc
->addToReferencedProjects(name
);
2077 const char *my_actcfg
= NULL
;
2079 char *my_args
[] = { NULL
};
2080 char **my_argv
= my_args
+ 0;
2082 boolean my_gflag
= *p_gflag
, my_aflag
= *p_aflag
, my_cflag
= *p_cflag
, // pass down
2083 my_Rflag
= *p_Rflag
, my_Pflag
= *p_Pflag
, my_Zflag
= *p_Zflag
, my_Hflag
= *p_Hflag
,
2084 my_sflag
= 0, my_Lflag
= 0, my_lflag
= 0, my_mflag
= 0, my_csflag
= 0,
2085 my_quflag
= 0, my_dsflag
= 0, my_dbflag
= 0, my_drflag
= 0,
2086 my_dtflag
= 0, my_dxflag
= 0, my_djflag
= 0, my_fxflag
= 0, my_doflag
= 0,
2087 my_gfflag
= 0, my_lnflag
= 0, my_isflag
= 0, my_asflag
= 0,
2088 my_swflag
= 0, my_Yflag
= 0, my_Mflag
= *p_Mflag
, my_Eflag
= 0, my_diflag
= *p_diflag
;
2090 char *my_ets
= NULL
;
2091 char *my_proj_name
= NULL
;
2092 autostring abs_projectLocationURI
;
2094 abs_projectLocationURI
= compose_path_name(abs_tpd_dir
, projectLocationURI
);
2096 //If absolute directory, then just copy the URI
2097 abs_projectLocationURI
= mcopystr(projectLocationURI
);
2100 char* sub_proj_abs_work_dir
= NULL
;
2102 tpd_result success
= process_tpd_internal((const char*)abs_projectLocationURI
, tpdName_loc
,
2103 my_actcfg
, file_list_path
, &my_argc
, &my_argv
, &my_optind
, &my_ets
, &my_proj_name
,
2104 &my_gflag
, &my_sflag
, &my_cflag
, &my_aflag
, preprocess
, &my_Rflag
, &my_lflag
,
2105 &my_mflag
, &my_Pflag
, &my_Lflag
, recursive
, force_overwrite
, gen_only_top_level
, NULL
, &sub_proj_abs_work_dir
,
2106 sub_project_dirs
, program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
, ttcn3_prep_defines
, ttcn3_prep_undefines
,
2107 prep_includes
, prep_defines
, prep_undefines
, &my_csflag
,
2108 &my_quflag
, &my_dsflag
, cxxcompiler
, optlevel
, optflags
, &my_dbflag
, &my_drflag
,
2109 &my_dtflag
, &my_dxflag
, &my_djflag
, &my_fxflag
, &my_doflag
,
2110 &my_gfflag
, &my_lnflag
, &my_isflag
, &my_asflag
, &my_swflag
, &my_Yflag
, &my_Mflag
, &my_Eflag
, &my_diflag
,
2111 solspeclibs
, sol8speclibs
, linuxspeclibs
, freebsdspeclibs
, win32speclibs
,
2112 ttcn3prep
, linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, FALSE
, &my_Zflag
,
2113 &my_Hflag
, NULL
, NULL
, prefix_workdir
, run_command_list
, seen_tpd_files
, required_configs
, profiled_file_list
,
2114 search_paths
, n_search_paths
);
2116 autostring
sub_proj_abs_work_dir_as(sub_proj_abs_work_dir
); // ?!
2118 if (success
== TPD_SUCCESS
) {
2119 my_actcfg
= get_act_config(required_configs
, my_proj_name
);
2120 if (recursive
) { // call ttcn3_makefilegen on referenced project's tpd file
2121 // -r is not needed any more because top level process traverses all projects recursively
2122 expstring_t command
= mprintf("%s -cVD", program_name
);
2123 if (force_overwrite
) command
= mputc(command
, 'f');
2124 if (prefix_workdir
) command
= mputc(command
, 'W');
2125 if (*p_gflag
) command
= mputc(command
, 'g');
2126 if (*p_sflag
) command
= mputc(command
, 's');
2127 if (*p_aflag
) command
= mputc(command
, 'a');
2128 if (*p_Rflag
) command
= mputc(command
, 'R');
2129 if (*p_lflag
) command
= mputc(command
, 'l');
2130 if (*p_mflag
) command
= mputc(command
, 'm');
2131 if (*p_Zflag
) command
= mputc(command
, 'Z');
2132 if (*p_Hflag
) command
= mputc(command
, 'H');
2133 command
= mputstr(command
, " -t ");
2134 command
= mputstr(command
, (const char*)abs_projectLocationURI
);
2136 command
= mputstr(command
, " -b ");
2137 command
= mputstr(command
, my_actcfg
);
2140 autostring
sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI
));
2141 const char * sub_proj_effective_work_dir
= sub_proj_abs_work_dir
? sub_proj_abs_work_dir
: (const char*)sub_tpd_dir
;
2142 if (!gen_only_top_level
) {
2143 if (run_command_list
) {
2144 // go to last element
2145 struct string2_list
* last_elem
= run_command_list
;
2146 while (last_elem
->next
) last_elem
= last_elem
->next
;
2147 // add strings to last element if empty or create new last element and add it to that
2148 if (last_elem
->str1
|| last_elem
->str2
) {
2149 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2150 last_elem
= last_elem
->next
;
2151 last_elem
->next
= NULL
;
2153 last_elem
->str1
= mcopystr(sub_proj_effective_work_dir
);
2154 last_elem
->str2
= command
;
2156 ERROR("Internal error: cannot add command to list");
2159 // add working dir to the end of list
2160 if (sub_project_dirs
) {
2161 // go to last element
2162 struct string_list
* last_elem
= sub_project_dirs
;
2163 while (last_elem
->next
) last_elem
= last_elem
->next
;
2164 // add string to last element if empty or create new last element and add it to that
2165 if (last_elem
->str
) {
2166 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
2167 last_elem
= last_elem
->next
;
2168 last_elem
->next
= NULL
;
2170 autostring
cwd_as(get_working_dir());
2171 last_elem
->str
= (*p_aflag
) ? mcopystr(sub_proj_effective_work_dir
) : get_relative_dir(sub_proj_effective_work_dir
, (const char*)cwd_as
);
2175 for (int z
= 0; z
< my_argc
; ++z
) {
2177 // central storage, keep in separate container
2178 base_files
.add(my_argv
[z
]); // string was allocated with new
2181 const cstring
tmp(my_argv
[z
]);
2182 if (!files
.has_key(tmp
)){
2183 files
.add(tmp
, my_argv
[z
]);
2190 Free(my_argv
); // free the array; we keep the pointers
2194 else if (success
== TPD_FAILED
) {
2195 ERROR("Failed to process %s", (const char*)abs_projectLocationURI
);
2196 result
= TPD_FAILED
;
2198 // else TPD_SKIPPED, keep quiet
2200 name
= projectLocationURI
= tpdName_loc
= NULL
; // forget all
2202 } // next referenced project
2206 if (get_path_status(output_file
) == PS_DIRECTORY
) {
2207 // points to existing dir; use as-is
2209 else { // we assume it points to a file: not our problem
2214 // (argc - optind) is the number of non-option arguments (assumed to be files)
2215 // given on the command line.
2216 int new_argc
= local_argc
- local_optind
+ files
.size() + base_files
.size();
2217 char ** new_argv
= (char**)Malloc(sizeof(char*) * new_argc
);
2221 // First, copy the filenames gathered from the TPD
2223 // We symlink the files into the working directory
2224 // and pass only the filename to the makefile generator
2225 for (int nf
= files
.size(); n
< nf
; ++n
) {
2226 const char *fn
= files
.get_nth_elem(n
); // relativeURI to the TPD location
2227 autostring
dir_n (get_dir_from_path (fn
));
2228 autostring
file_n(get_file_from_path(fn
));
2229 autostring
rel_n (get_absolute_dir(dir_n
, abs_tpd_dir
, TRUE
));
2230 autostring
abs_n (compose_path_name(rel_n
, file_n
));
2232 if (local_argc
== 0) {
2233 // We are being invoked recursively, for a referenced TPD.
2234 // Do not symlink; just return absolute paths to the files.
2237 // compose with workdir
2238 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
2240 // it's an absolute path, copy verbatim
2241 new_argv
[n
] = mcopystr(fn
); // fn will be destroyed, pass a copy
2244 else { // relative path
2246 // compose with workdir
2247 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
2248 // Do not call file_n.extract() : the composed path will be returned,
2249 // its component will need to be deallocated here.
2252 // compose with tpd dir
2253 new_argv
[n
] = const_cast<char*>(abs_n
.extract());
2257 else { // we are processing the top-level TPD
2260 int fd
= open(abs_n
, O_RDONLY
);
2261 if (fd
>= 0) { // successfully opened
2264 file_n
= compose_path_name(output_file
, file_n
);
2266 //TODO ! compose with output_file
2267 // save into list: add symlink data to the end of list
2268 if (create_symlink_list
) {
2269 // go to last element
2270 struct string2_list
* last_elem
= create_symlink_list
;
2271 while (last_elem
->next
) last_elem
= last_elem
->next
;
2272 // add strings to last element if empty or create new last element and add it to that
2273 if (last_elem
->str1
) {
2274 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
2275 last_elem
= last_elem
->next
;
2276 last_elem
->next
= NULL
;
2278 last_elem
->str1
= mcopystr(abs_n
);
2279 last_elem
->str2
= mcopystr(file_n
);
2283 ERROR("%s does not exist", (const char*)abs_n
);
2289 puts((const char *)abs_n
);
2291 autostring
dir_part(get_dir_from_path(abs_n
));
2292 autostring
file_part(get_file_from_path(abs_n
));
2293 autostring
rel_dir_part(get_relative_dir((const char *)dir_part
, file_list_path
? file_list_path
: (const char *)abs_tpd_dir
));
2294 autostring
rel_dir_file_part(compose_path_name((const char *)rel_dir_part
, (const char *)file_part
));
2295 puts((const char *)rel_dir_file_part
);
2298 new_argv
[n
] = const_cast<char *>(file_n
.extract());
2301 // Print the TPD too.
2303 autostring
dir_part(get_dir_from_path(p_tpd_name
));
2304 autostring
file_part(get_file_from_path(p_tpd_name
));
2306 puts((const char *)abs_tpd_name
);
2308 autostring
rel_dir_part(get_relative_dir(dir_part
, file_list_path
? file_list_path
: abs_tpd_dir
));
2309 autostring
rel_dir_file_part(compose_path_name(rel_dir_part
, file_part
));
2310 const char *rel_tpd_name
= (const char *)rel_dir_file_part
;
2315 // base_files from referenced projects
2316 for (size_t bf
= 0, bs
= base_files
.size(); bf
< bs
; ++bf
, ++n
) {
2317 new_argv
[n
] = base_files
[bf
];
2319 base_files
.clear(); // string ownership transfered
2321 // Then, copy the filenames from the command line.
2322 for (int a
= *p_optind
; a
< *p_argc
; ++a
, ++n
) {
2323 // String may be from main's argv; copy to the heap.
2324 new_argv
[n
] = mcopystr((*p_argv
)[a
]);
2327 if (local_argc
> 0) { // it is the outermost call
2328 clear_seen_tpd_files(seen_tpd_files
);
2336 for (size_t i
= 0, e
= files
.size(); i
< e
; ++i
) {
2337 Free(const_cast<char*>(files
.get_nth_elem(i
)));
2341 for (size_t i
= 0, e
= folders
.size(); i
< e
; ++i
) {
2342 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
2347 Free((char*)p_tpd_name
);
2350 excluded_files
.clear();
2351 excluded_folders
.clear();