1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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
7 ///////////////////////////////////////////////////////////////////////////////
16 #include <sys/types.h>
20 #include <libxml/parser.h>
21 #include <libxml/tree.h>
22 #include <libxml/xpath.h>
24 #define LIBXML_SCHEMAS_ENABLED
25 #include <libxml/xmlschemastypes.h>
27 #include "../common/memory.h"
29 // Do _NOT_ #include "string.hh", it drags in ustring.o, common/Quadruple.o,
30 // Int.o, ttcn3/PatternString.o, and then the entire AST :(
32 #include "../common/path.h"
35 void ERROR (const char *fmt
, ...);
36 void WARNING(const char *fmt
, ...);
37 void NOTIFY (const char *fmt
, ...);
38 void DEBUG (const char *fmt
, ...);
41 void fatal_error(const char * filename
, int lineno
, const char * fmt
, ...)
42 __attribute__ ((__format__ (__printf__
, 3, 4), __noreturn__
));
44 void fatal_error(const char * filename
, int lineno
, const char * fmt
, ...)
46 fputs(filename
, stderr
);
47 fprintf(stderr
, ":%d: ", lineno
);
50 vfprintf(stderr
, fmt
, va
);
55 /// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
56 xmlXPathObjectPtr
run_xpath(xmlXPathContextPtr xpathCtx
, const char *xpathExpr
)
58 xmlXPathObjectPtr xpathObj
= xmlXPathEvalExpression(
59 (const xmlChar
*)xpathExpr
, xpathCtx
);
60 if(xpathObj
== NULL
) {
61 fprintf(stderr
,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr
);
72 explicit XmlDoc(xmlDocPtr p
) : doc_(p
) {}
74 if (doc_
!= NULL
) xmlFreeDoc(doc_
);
76 operator xmlDocPtr() const { return doc_
; }
83 explicit XPathContext(xmlXPathContextPtr c
) : ctx_(c
) {}
85 if (ctx_
!= NULL
) xmlXPathFreeContext(ctx_
);
87 operator xmlXPathContextPtr() const { return ctx_
; }
89 xmlXPathContextPtr ctx_
;
94 explicit XPathObject(xmlXPathObjectPtr o
) : xpo_(o
) {}
96 if (xpo_
!= NULL
) xmlXPathFreeObject(xpo_
);
98 operator xmlXPathObjectPtr() const { return xpo_
; }
99 xmlXPathObjectPtr
operator->() const { return xpo_
; }
101 xmlXPathObjectPtr xpo_
;
104 //------------------------------------------------------------------
105 /// compare-by-content wrapper of a plain C string
107 explicit cstring(const char *s
) : str(s
) {}
108 void destroy() const;
109 operator const char*() const { return str
; }
112 friend boolean
operator<(const cstring
& l
, const cstring
& r
);
113 friend boolean
operator==(const cstring
& l
, const cstring
& r
);
116 void cstring::destroy() const {
117 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
120 boolean
operator<(const cstring
& l
, const cstring
& r
) {
121 return strcmp(l
.str
, r
.str
) < 0;
124 boolean
operator==(const cstring
& l
, const cstring
& r
) {
125 return strcmp(l
.str
, r
.str
) == 0;
128 /// RAII for C string
129 struct autostring
: public cstring
{
130 /// Constructor; takes over ownership
131 explicit autostring(const char *s
= 0) : cstring(s
) {}
133 // He who can destroy a thing, controls that thing -- Paul Muad'Dib
134 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
136 /// %Assignment; takes over ownership
137 const autostring
& operator=(const char *s
) {
138 Free(const_cast<char*>(str
)); // assumes valid pointer or NULL
142 /// Relinquish ownership
143 const char *extract() {
144 const char *retval
= str
;
149 autostring(const autostring
&);
150 autostring
& operator=(const autostring
&);
154 bool validate_tpd(const XmlDoc
& xml_doc
, const char* tpd_file_name
, const char* xsd_file_name
)
156 xmlLineNumbersDefault(1);
158 xmlSchemaParserCtxtPtr ctxt
= xmlSchemaNewParserCtxt(xsd_file_name
);
160 ERROR("Unable to create xsd context for xsd file `%s'", xsd_file_name
);
163 xmlSchemaSetParserErrors(ctxt
, (xmlSchemaValidityErrorFunc
)fprintf
, (xmlSchemaValidityWarningFunc
)fprintf
, stderr
);
165 xmlSchemaPtr schema
= xmlSchemaParse(ctxt
);
167 ERROR("Unable to parse xsd file `%s'", xsd_file_name
);
168 xmlSchemaFreeParserCtxt(ctxt
);
172 xmlSchemaValidCtxtPtr xsd
= xmlSchemaNewValidCtxt(schema
);
174 ERROR("Schema validation error for xsd file `%s'", xsd_file_name
);
175 xmlSchemaFree(schema
);
176 xmlSchemaFreeParserCtxt(ctxt
);
179 xmlSchemaSetValidErrors(xsd
, (xmlSchemaValidityErrorFunc
) fprintf
, (xmlSchemaValidityWarningFunc
) fprintf
, stderr
);
181 int ret
= xmlSchemaValidateDoc(xsd
, xml_doc
);
183 xmlSchemaFreeValidCtxt(xsd
);
184 xmlSchemaFree(schema
);
185 xmlSchemaFreeParserCtxt(ctxt
);
186 xmlSchemaCleanupTypes();
189 return true; // successful validation
191 ERROR("TPD file `%s' is invalid according to schema `%s'", tpd_file_name
, xsd_file_name
);
194 ERROR("TPD validation of `%s' generated an internal error in libxml2", tpd_file_name
);
199 /** Extract a boolean value from the XML, if it exists otherwise flag is unchanged
201 * @param xpathCtx XPath context object
202 * @param actcfg name of the active configuration
203 * @param option name of the value
204 * @param flag pointer to the variable to receive the value
206 void xsdbool2boolean(const XPathContext
& xpathCtx
, const char *actcfg
,
207 const char *option
, boolean
* flag
)
209 char *xpath
= mprintf(
210 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
211 "/ProjectProperties/MakefileSettings/%s[text()='true']",
213 XPathObject
xpathObj(run_xpath(xpathCtx
, xpath
));
216 if (xpathObj
->nodesetval
&& xpathObj
->nodesetval
->nodeNr
> 0) {
221 // data structures and functions to manage excluded folders/files
223 map
<cstring
, void> excluded_files
;
225 boolean
is_excluded_file(const cstring
& path
) {
226 return excluded_files
.has_key(path
);
229 vector
<const char> excluded_folders
;
231 // Unfortunately, when "docs" is excluded, we need to drop
232 // files in "docs/", "docs/pdf/", "docs/txt/", "docs/txt/old/" etc;
233 // so it's not as simple as using a map :(
235 /** Checks whether a file is under an excluded folder
237 * @param path (relative) path of the file
238 * @return true if file is excluded, false otherwise
240 boolean
is_excluded_folder(const char *path
) {
241 boolean answer
= FALSE
;
242 size_t pathlen
= strlen(path
);
244 for (size_t i
= 0, end
= excluded_folders
.size(); i
< end
; ++i
) {
245 const char *xdir
= excluded_folders
[i
];
246 size_t xdlen
= strlen(xdir
);
247 if (pathlen
> xdlen
&& path
[xdlen
] == '/') {
248 // we may have a winner
249 if ((answer
= !strncmp(path
, xdir
, xdlen
))) break;
255 // How do you treat a raw info? You cook it, of course!
256 // Returns a newly allocated string.
257 char *cook(const char *raw
, const map
<cstring
, const char>& path_vars
)
259 const char *slash
= strchr(raw
, '/');
260 if (!slash
) { // Pretend that the slash is at the end of the string.
261 slash
= raw
+ strlen(raw
);
264 // Assume that a path variable reference is the first (or only) component
265 // of the path: ROOT in "ROOT/etc/issue".
266 autostring
prefix(mcopystrn(raw
, slash
- raw
));
267 if (path_vars
.has_key(prefix
)) {
268 char *cooked
= mcopystr(path_vars
[prefix
]);
269 bool ends_with_slash
= cooked
[strlen(cooked
)-1] == '/';
270 if (ends_with_slash
&& *slash
== '/') {
271 // Avoid paths with two slashes at the start; Cygwin thinks it's UNC
274 // If there was no '/' (only the path variable reference e.g "ROOT")
275 // then slash points to a null byte and the mputstr is a no-op.
276 cooked
= mputstr(cooked
, slash
);
280 // If the path variable could not be substituted,
281 // return (a copy of) the original.
282 return mcopystr(raw
);
285 void replacechar(char** content
) {
287 std::string s
= *content
;
289 while ((found
= s
.find('['))!= std::string::npos
){
290 s
.replace(found
,1, "${");
292 while ((found
= s
.find(']')) != std::string::npos
){
293 s
.replace(found
,1, "}");
295 *content
= mcopystr(s
.c_str());
298 static void clear_seen_tpd_files(map
<cstring
, int>& seen_tpd_files
) {
299 for (size_t i
= 0, num
= seen_tpd_files
.size(); i
< num
; ++i
) {
300 const cstring
& key
= seen_tpd_files
.get_nth_key(i
);
301 int *elem
= seen_tpd_files
.get_nth_elem(i
);
305 seen_tpd_files
.clear();
308 static tpd_result
process_tpd_internal(const char *p_tpd_name
, const char *actcfg
,
309 const char *file_list_path
, int *p_argc
, char ***p_argv
,
310 int *p_optind
, char **p_ets_name
,
311 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
312 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
313 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
314 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
315 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
316 struct string_list
* ttcn3_prep_defines
, struct string_list
* prep_includes
, struct string_list
* prep_defines
,
317 boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
, char** cxxcompiler
,
318 char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
, boolean
* p_djflag
,
319 boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
320 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
321 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
322 struct string_list
* linkerlibs
, struct string_list
* additionalObjects
, struct string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
,
323 char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
, struct string2_list
* run_command_list
,
324 map
<cstring
, int>& seen_tpd_files
);
326 extern "C" tpd_result
process_tpd(const char *p_tpd_name
, const char *actcfg
,
327 const char *file_list_path
, int *p_argc
, char ***p_argv
,
328 int *p_optind
, char **p_ets_name
,
329 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
330 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
331 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
332 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
333 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
334 struct string_list
* ttcn3_prep_defines
, struct string_list
* prep_includes
, struct string_list
* prep_defines
,
335 boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
, char** cxxcompiler
,
336 char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
, boolean
* p_djflag
,
337 boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
338 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
339 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
340 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
,
341 char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
, struct string2_list
* run_command_list
) {
343 map
<cstring
, int> seen_tpd_files
;
345 tpd_result success
= process_tpd_internal(p_tpd_name
,
346 actcfg
, file_list_path
, p_argc
, p_argv
, p_optind
, p_ets_name
,
347 p_gflag
, p_sflag
, p_cflag
, p_aflag
, preprocess
,
348 p_Rflag
, p_lflag
, p_mflag
, p_Pflag
,
349 p_Lflag
, recursive
, force_overwrite
, gen_only_top_level
,
350 output_file
, abs_work_dir_p
, sub_project_dirs
,
351 program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
,
352 ttcn3_prep_defines
, prep_includes
, prep_defines
,
353 p_csflag
, p_quflag
, p_dsflag
, cxxcompiler
,
354 optlevel
, optflags
, p_dbflag
, p_drflag
, p_dtflag
, p_dxflag
, p_djflag
,
355 p_fxflag
, p_doflag
, p_gfflag
, p_lnflag
, p_isflag
,
356 p_asflag
, p_swflag
, p_Yflag
, solspeclibs
, sol8speclibs
,
357 linuxspeclibs
, freebsdspeclibs
, win32speclibs
, ttcn3prep
,
358 linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, Dflag
,
359 generatorCommandOutput
, target_placement_list
, prefix_workdir
, run_command_list
, seen_tpd_files
);
361 for (size_t i
= 0, num
= seen_tpd_files
.size(); i
< num
; ++i
) {
362 const cstring
& key
= seen_tpd_files
.get_nth_key(i
);
363 int *elem
= seen_tpd_files
.get_nth_elem(i
);
367 seen_tpd_files
.clear();
372 // optind is the index of the next element of argv to be processed.
373 // Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
374 // seen already, or TPD_FAILED.
376 // Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
377 // (argv[], ets_name, other_files[], output_file) are allocated on the heap
378 // and need to be freed. On input, these strings point into argv.
379 // process_tpd() may alter these strings; new values will be on the heap.
380 // If process_tpd() preserves the content of such a string (e.g. ets_name),
381 // it must nevertheless make a copy on the heap via mcopystr().
382 static tpd_result
process_tpd_internal(const char *p_tpd_name
, const char *actcfg
,
383 const char *file_list_path
, int *p_argc
, char ***p_argv
,
384 int *p_optind
, char **p_ets_name
,
385 boolean
*p_gflag
, boolean
*p_sflag
, boolean
*p_cflag
, boolean
*p_aflag
, boolean
*preprocess
,
386 boolean
*p_Rflag
, boolean
*p_lflag
, boolean
*p_mflag
, boolean
*p_Pflag
,
387 boolean
*p_Lflag
, boolean recursive
, boolean force_overwrite
, boolean gen_only_top_level
,
388 const char *output_file
, char** abs_work_dir_p
, struct string_list
* sub_project_dirs
,
389 const char* program_name
, FILE* prj_graph_fp
, struct string2_list
* create_symlink_list
, struct string_list
* ttcn3_prep_includes
,
390 struct string_list
* ttcn3_prep_defines
, struct string_list
* prep_includes
, struct string_list
* prep_defines
,
391 boolean
*p_csflag
, boolean
*p_quflag
, boolean
* p_dsflag
, char** cxxcompiler
,
392 char** optlevel
, char** optflags
, boolean
* p_dbflag
, boolean
* p_drflag
, boolean
* p_dtflag
, boolean
* p_dxflag
, boolean
* p_djflag
,
393 boolean
* p_fxflag
, boolean
* p_doflag
, boolean
* p_gfflag
, boolean
* p_lnflag
, boolean
* p_isflag
,
394 boolean
* p_asflag
, boolean
* p_swflag
, boolean
* p_Yflag
, struct string_list
* solspeclibs
, struct string_list
* sol8speclibs
,
395 struct string_list
* linuxspeclibs
, struct string_list
* freebsdspeclibs
, struct string_list
* win32speclibs
, char** ttcn3prep
,
396 string_list
* linkerlibs
, string_list
* additionalObjects
, string_list
* linkerlibsearchp
, boolean Vflag
, boolean Dflag
,
397 char** generatorCommandOutput
, struct string2_list
* target_placement_list
, boolean prefix_workdir
, struct string2_list
* run_command_list
,
398 map
<cstring
, int>& seen_tpd_files
)
400 // read-only non-pointer aliases
401 //char** const& local_argv = *p_argv;
402 int const& local_argc
= *p_argc
;
403 int const& local_optind
= *p_optind
;
404 *abs_work_dir_p
= NULL
;
406 assert(local_optind
>= 2 // at least '-ttpd_name' must be in the args
407 || local_optind
== 0); // if called for a referenced project
409 assert(local_argc
>= local_optind
);
411 autostring
tpd_dir(get_dir_from_path(p_tpd_name
));
412 autostring
abs_tpd_dir(get_absolute_dir(tpd_dir
, NULL
));
414 autostring
tpd_filename(get_file_from_path(p_tpd_name
));
415 autostring
abs_tpd_name(compose_path_name(abs_tpd_dir
, tpd_filename
));
417 if (seen_tpd_files
.has_key(abs_tpd_name
)) {
418 ++*seen_tpd_files
[abs_tpd_name
];
419 return TPD_SKIPPED
; // nothing to do
422 if (recursive
&& !prefix_workdir
) {
423 // check that this tpd file is not inside a directory of another tpd file
424 for (size_t i
= 0; i
< seen_tpd_files
.size(); ++i
) {
425 const cstring
& other_tpd_name
= seen_tpd_files
.get_nth_key(i
);
426 autostring
other_tpd_dir(get_dir_from_path((const char*)other_tpd_name
));
427 if (strcmp((const char*)abs_tpd_dir
,(const char*)other_tpd_dir
)==0) {
428 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
);
433 // mcopystr makes another copy for the map
434 seen_tpd_files
.add(cstring(mcopystr(abs_tpd_name
)), new int(1));
437 vector
<char> base_files
; // values Malloc'd but we pass them to the caller
439 XmlDoc
doc(xmlParseFile(p_tpd_name
));
441 fprintf(stderr
, "Error: unable to parse file \"%s\"\n", p_tpd_name
);
446 // try schema validation if tpd schema file was found
447 bool tpd_is_valid
= false;
448 const char* ttcn3_dir
= getenv("TTCN3_DIR");
450 size_t ttcn3_dir_len
= strlen(ttcn3_dir
);
451 bool ends_with_slash
= (ttcn3_dir_len
>0) && (ttcn3_dir
[ttcn3_dir_len
- 1]=='/');
452 expstring_t xsd_file_name
= mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir
, ends_with_slash
?"":"/");
453 autostring
xsd_file_name_as(xsd_file_name
);
454 if (get_path_status(xsd_file_name
)==PS_FILE
) {
455 if (validate_tpd(doc
, p_tpd_name
, xsd_file_name
)) {
457 NOTIFY("TPD file `%s' validated successfully with schema file `%s'", p_tpd_name
, xsd_file_name
);
460 ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name
);
463 ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
471 // Key is projectRelativePath, value is relativeURI or rawURI.
472 map
<cstring
, const char> files
; // values Malloc'd
473 map
<cstring
, const char> folders
; // values Malloc'd
474 // NOTE! files and folders must be local variables of process_tpd.
475 // This is because the keys (not the values) are owned by the XmlDoc.
477 map
<cstring
, const char> path_vars
;
479 XPathContext
xpathCtx(xmlXPathNewContext(doc
));
480 if (xpathCtx
== NULL
) {
481 fprintf(stderr
,"Error: unable to create new XPath context\n");
484 // Collect path variables
486 XPathObject
pathsObj(run_xpath(xpathCtx
,
487 "/TITAN_Project_File_Information/PathVariables/PathVariable"));
488 xmlNodeSetPtr nodes
= pathsObj
->nodesetval
;
490 const char *name
= 0, *value
= 0;
491 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
492 // nodes->nodeTab[i]->name === "PathVariable"
493 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
494 if (!strcmp((const char*)attr
->name
, "name")) {
495 name
= (const char*)attr
->children
->content
;
497 else if (!strcmp((const char*)attr
->name
, "value")) {
498 value
= (const char*)attr
->children
->content
;
501 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
505 if (name
&& value
) path_vars
.add(cstring(name
), value
);
506 else ERROR("A PathVariable must have both name and value");
507 } // next PathVariable
512 XPathObject
foldersObj(run_xpath(xpathCtx
,
513 "/TITAN_Project_File_Information/Folders/FolderResource"));
515 xmlNodeSetPtr nodes
= foldersObj
->nodesetval
;
516 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
517 // nodes->nodeTab[i]->name === "FolderResource"
518 const char *uri
= 0, *path
= 0, *raw
= 0;
520 // projectRelativePath is the path as it appears in Project Explorer (illusion)
521 // relativeURI is the actual location, relative to the project root (reality)
522 // rawURI is present if the relative path can not be calculated
524 // Theoretically these attributes could be in any order, loop over them
525 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
526 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
527 path
= (const char*)attr
->children
->content
;
529 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
530 uri
= (const char*)attr
->children
->content
;
532 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
533 raw
= (const char*)attr
->children
->content
;
536 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
541 ERROR("A FolderResource must have a projectRelativePath");
545 if (uri
== NULL
&& raw
== NULL
) {
546 ERROR("A FolderResource must have either relativeURI or rawURI");
549 // relativeURI wins over rawURI
550 folders
.add(cstring(path
), uri
? mcopystr(uri
) : cook(raw
, path_vars
));
551 // TODO uri: cut "file:", complain on anything else
552 } // next FolderResource
557 // Find out the active config
558 XPathObject
activeConfig(run_xpath(xpathCtx
,
559 "/TITAN_Project_File_Information/ActiveConfiguration/text()"));
560 if (activeConfig
->nodesetval
&& activeConfig
->nodesetval
->nodeNr
== 1) {
562 actcfg
= (const char*)activeConfig
->nodesetval
->nodeTab
[0]->content
;
566 if (actcfg
== NULL
) {
567 ERROR("Can not find the active build configuration.");
568 for (size_t i
= 0; i
< folders
.size(); ++i
) {
569 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
575 { // check if the active configuration exists
576 expstring_t xpathActCfg
= mprintf(
577 "/TITAN_Project_File_Information/Configurations/"
578 "Configuration[@name='%s']/text()", actcfg
);
579 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfg
));
582 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
584 ERROR("The active build configuration named '%s' does not exist",
586 for (size_t i
= 0; i
< folders
.size(); ++i
) {
587 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
594 /////////////////////////////////////////////////////////////////////////////
595 // working directory stuff
598 const char* workdirFromTpd
= "bin"; // default value
599 char *workdirXpath
= mprintf(
600 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
601 "/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
603 XPathObject
workdirObj(run_xpath(xpathCtx
, workdirXpath
));
605 if (workdirObj
->nodesetval
&& workdirObj
->nodesetval
->nodeNr
> 0) {
606 workdirFromTpd
= (const char*)workdirObj
->nodesetval
->nodeTab
[0]->content
;
608 if (prefix_workdir
) { // the working directory is: prjNameStr + "_" + workdirFromTpd
609 const char* prjNameStr
= "unnamedproject";
610 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
611 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
612 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
614 workdir
= mprintf("%s_%s", prjNameStr
, workdirFromTpd
);
616 workdir
= mcopystr(workdirFromTpd
);
619 if (!folders
.has_key(workdir
)) {
620 // Maybe the tpd was saved with the option "No info about work dir"
621 folders
.add(workdir
, mcopystr(workdir
)); // fake it
623 const char *real_workdir
= folders
[workdir
]; // This is relative to the location of the tpd file
624 excluded_folders
.add(real_workdir
); // excluded by convention
626 autostring abs_workdir
;
627 // If -D flag was specified then we ignore the workdir
628 // in the TPD (the current dir is considered the work dir).
630 bool hasWorkDir
= false;
631 // if the working directory does not exist create it
632 autostring
saved_work_dir(get_working_dir());
633 if (set_working_dir(abs_tpd_dir
)) {
634 ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir
);
636 switch (get_path_status(real_workdir
)) {
638 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
);
645 if (recursive
|| local_argc
!= 0) { // we only want to create workdir if necessary
646 printf("Working directory `%s' in project `%s' does not exist, trying to create it...\n", real_workdir
, (const char*)abs_tpd_dir
);
647 int rv
= mkdir(real_workdir
, 0755);
648 if (rv
) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno
));
649 else printf("Working directory created\n");
655 if (local_argc
==0) { // if not top level
656 set_working_dir(saved_work_dir
); // restore working directory
657 } else { // if top level
658 set_working_dir(real_workdir
); // go into the working dir
660 if (hasWorkDir
) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
661 *abs_work_dir_p
= get_absolute_dir(real_workdir
, abs_tpd_dir
);
662 abs_workdir
= (mcopystr(*abs_work_dir_p
));
665 /////////////////////////////////////////////////////////////////////////////
667 // Gather the excluded folders in the active config
669 expstring_t xpathActCfgPaths
= mprintf(
670 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
671 "/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
672 // This was the selection criterium, we need to go up and down for the actual information
673 "/parent::*/parent::*/FolderPath/text()",
675 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
676 Free(xpathActCfgPaths
);
678 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
679 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
681 excluded_folders
.add((const char*)nodes
->nodeTab
[i
]->content
);
685 // Gather individual excluded files in the active config
687 expstring_t xpathActCfgPaths
= mprintf(
688 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
689 "/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
690 "/parent::*/parent::*/FilePath/text()",
692 XPathObject
theConfigEx(run_xpath(xpathCtx
, xpathActCfgPaths
));
693 Free(xpathActCfgPaths
);
695 xmlNodeSetPtr nodes
= theConfigEx
->nodesetval
;
696 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
697 xmlNodePtr curnode
= nodes
->nodeTab
[i
];
699 cstring
aa((const char*)curnode
->content
);
700 excluded_files
.add(aa
, 0);
704 // Collect files; filter out excluded ones
706 XPathObject
filesObj(run_xpath(xpathCtx
,
707 "TITAN_Project_File_Information/Files/FileResource"));
709 xmlNodeSetPtr nodes
= filesObj
->nodesetval
;
710 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
711 // nodes->nodeTab[i]->name === "FileResource"
712 const char *uri
= 0, *path
= 0, *raw
= 0;
714 // projectRelativePath is the path as it appears in Project Explorer (illusion)
715 // relativeURI is the actual location, relative to the project root (reality)
716 // rawURI is present if the relative path can not be calculated
718 // Theoretically these attributes could be in any order, loop over them
719 for (xmlAttrPtr attr
= nodes
->nodeTab
[i
]->properties
; attr
; attr
= attr
->next
) {
720 if (!strcmp((const char*)attr
->name
, "projectRelativePath")) {
721 path
= (const char*)attr
->children
->content
;
723 else if (!strcmp((const char*)attr
->name
, "relativeURI")) {
724 uri
= (const char*)attr
->children
->content
;
726 else if (!strcmp((const char*)attr
->name
, "rawURI")) {
727 raw
= (const char*)attr
->children
->content
;
730 WARNING("Unknown attribute %s", (const char*)nodes
->nodeTab
[i
]->name
);
735 ERROR("A FileResource must have a projectRelativePath");
739 if (uri
== NULL
&& raw
== NULL
) {
740 ERROR("A FileResource must have either relativeURI or rawURI");
745 if (!is_excluded_file(cpath
) && !is_excluded_folder(path
)) {
746 // relativeURI wins over rawURI
747 char *ruri
= uri
? mcopystr(uri
) : cook(raw
, path_vars
);
749 if (files
.has_key(cpath
)) {
750 ERROR("A FileResource %s must be unique!", (const char*)cpath
);
752 files
.add(cpath
, ruri
); // relativeURI to the TPD location
753 { // set the *preprocess value if .ttcnpp file was found
754 const size_t ttcnpp_extension_len
= 7; // ".ttcnpp"
755 const size_t ruri_len
= strlen(ruri
);
756 if ( ruri_len
>ttcnpp_extension_len
&& strcmp(ruri
+(ruri_len
-ttcnpp_extension_len
),".ttcnpp")==0 ) {
762 } // next FileResource
766 xsdbool2boolean(xpathCtx
, actcfg
, "useAbsolutePath", p_aflag
);
767 xsdbool2boolean(xpathCtx
, actcfg
, "GNUMake", p_gflag
);
768 xsdbool2boolean(xpathCtx
, actcfg
, "dynamicLinking", p_lflag
);
769 xsdbool2boolean(xpathCtx
, actcfg
, "functiontestRuntime", p_Rflag
);
770 xsdbool2boolean(xpathCtx
, actcfg
, "singleMode", p_sflag
);
771 xsdbool2boolean(xpathCtx
, actcfg
, "codeSplitting", p_csflag
);
772 xsdbool2boolean(xpathCtx
, actcfg
, "quietly", p_quflag
);
773 xsdbool2boolean(xpathCtx
, actcfg
, "disableSubtypeChecking", p_dsflag
);
774 xsdbool2boolean(xpathCtx
, actcfg
, "disableBER", p_dbflag
);
775 xsdbool2boolean(xpathCtx
, actcfg
, "disableRAW", p_drflag
);
776 xsdbool2boolean(xpathCtx
, actcfg
, "disableTEXT", p_dtflag
);
777 xsdbool2boolean(xpathCtx
, actcfg
, "disableXER", p_dxflag
);
778 xsdbool2boolean(xpathCtx
, actcfg
, "disableJSON", p_djflag
);
779 xsdbool2boolean(xpathCtx
, actcfg
, "forceXERinASN.1", p_fxflag
);
780 xsdbool2boolean(xpathCtx
, actcfg
, "defaultasOmit", p_doflag
);
781 xsdbool2boolean(xpathCtx
, actcfg
, "gccMessageFormat", p_gfflag
);
782 xsdbool2boolean(xpathCtx
, actcfg
, "lineNumbersOnlyInMessages", p_lnflag
);
783 xsdbool2boolean(xpathCtx
, actcfg
, "includeSourceInfo", p_isflag
);
784 xsdbool2boolean(xpathCtx
, actcfg
, "addSourceLineInfo", p_asflag
);
785 xsdbool2boolean(xpathCtx
, actcfg
, "suppressWarnings", p_swflag
);
786 xsdbool2boolean(xpathCtx
, actcfg
, "outParamBoundness", p_Yflag
);
788 // Extract the "incremental dependencies" option
790 boolean incremental_deps
= TRUE
;
791 xsdbool2boolean(xpathCtx
, actcfg
, "incrementalDependencyRefresh", &incremental_deps
);
793 // For makefilegen, "Use GNU make" implies incremental deps by default,
794 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
795 // For Eclipse, incremental deps must be explicitly specified,
796 // even if GNU make is being used.
798 if (incremental_deps
) {
800 WARNING("Incremental dependency ordered but it requires gnu make");
805 // GNU make but no incremental deps
811 // Extract the default target option
812 // if it is not defined as a command line argument
814 char *defTargetXpath
= mprintf(
815 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
816 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
818 XPathObject
defTargetObj(run_xpath(xpathCtx
, defTargetXpath
));
819 Free(defTargetXpath
);
820 if (defTargetObj
->nodesetval
&& defTargetObj
->nodesetval
->nodeNr
> 0) {
821 const char* content
= (const char*)defTargetObj
->nodesetval
->nodeTab
[0]->content
;
822 if (!strcmp(content
, "library")) {
824 } else if (!strcmp(content
, "executable")) {
827 ERROR("Unknown default target: '%s'."
828 " The available targets are: 'executable', 'library'", content
);
833 // Executable name (don't care unless top-level invocation)
836 char *exeXpath
= mprintf(
837 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
838 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
840 XPathObject
exeObj(run_xpath(xpathCtx
, exeXpath
));
842 if (exeObj
->nodesetval
&& exeObj
->nodesetval
->nodeNr
> 0) {
843 const char* target_executable
= (const char*)exeObj
->nodesetval
->nodeTab
[0]->content
;
844 autostring
target_exe_dir(get_dir_from_path(target_executable
));
845 autostring
target_exe_file(get_file_from_path(target_executable
));
846 if (target_exe_dir
!=NULL
) { // if it's not only a file name
847 if (get_path_status(target_exe_dir
)==PS_NONEXISTENT
) {
848 if (strcmp(real_workdir
,target_exe_dir
)!=0) {
849 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
);
851 target_executable
= target_exe_file
;
854 if (!*p_ets_name
) { // Command line will win
855 *p_ets_name
= mcopystr(target_executable
);
860 // create an xml element for the currently processed project
862 const char* prjNameStr
= "???";
863 XPathObject
prjName(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ProjectName/text()"));
864 if (prjName
->nodesetval
&& prjName
->nodesetval
->nodeNr
== 1) {
865 prjNameStr
= (const char*)prjName
->nodesetval
->nodeTab
[0]->content
;
867 autostring
tpd_rel_dir(get_relative_dir(tpd_dir
, NULL
));
868 autostring
tpd_rel_path(compose_path_name(tpd_rel_dir
, (const char*)tpd_filename
));
869 fprintf(prj_graph_fp
, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr
, (const char*)tpd_rel_path
);
870 XPathObject
subprojects(run_xpath(xpathCtx
, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
871 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
872 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
873 const char* refd_name
= "???";
874 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
875 refd_name
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
877 fprintf(prj_graph_fp
, "<reference name=\"%s\"/>\n", refd_name
);
879 fprintf(prj_graph_fp
, "</project>\n");
882 // Tpd part of the MakefileSettings
884 //TTCN3preprocessorIncludes
885 char *preincludeXpath
= mprintf(
886 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
887 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
889 XPathObject
preincludeObj(run_xpath(xpathCtx
, preincludeXpath
));
890 Free(preincludeXpath
);
892 xmlNodeSetPtr nodes
= preincludeObj
->nodesetval
;
894 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
895 char* content
= (char*)preincludeObj
->nodesetval
->nodeTab
[i
]->content
;
897 // add includes to the end of list
898 if (ttcn3_prep_includes
) {
899 // go to last element
900 struct string_list
* last_elem
= ttcn3_prep_includes
;
901 while (last_elem
->next
) last_elem
= last_elem
->next
;
902 // add string to last element if empty or create new last element and add it to that
903 if (last_elem
->str
) {
904 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
905 last_elem
= last_elem
->next
;
906 last_elem
->next
= NULL
;
908 replacechar(&content
);
909 last_elem
->str
= content
;
914 //TTCN3preprocessorDefines
915 char *ttcn3predefinesXpath
= mprintf(
916 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
917 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
919 XPathObject
ttcn3predefinesObj(run_xpath(xpathCtx
, ttcn3predefinesXpath
));
920 Free(ttcn3predefinesXpath
);
922 xmlNodeSetPtr nodes
= ttcn3predefinesObj
->nodesetval
;
924 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
925 const char* content
= (const char*)ttcn3predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
927 // add includes to the end of list
928 if (ttcn3_prep_defines
) {
929 // go to last element
930 struct string_list
* last_elem
= ttcn3_prep_defines
;
931 while (last_elem
->next
) last_elem
= last_elem
->next
;
932 // add string to last element if empty or create new last element and add it to that
933 if (last_elem
->str
) {
934 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
935 last_elem
= last_elem
->next
;
936 last_elem
->next
= NULL
;
938 last_elem
->str
= mcopystr(content
);
943 //preprocessorIncludes
944 char *preincludesXpath
= mprintf(
945 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
946 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
948 XPathObject
preincludesObj(run_xpath(xpathCtx
, preincludesXpath
));
949 Free(preincludesXpath
);
951 xmlNodeSetPtr nodes
= preincludesObj
->nodesetval
;
953 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
954 char* content
= (char*)preincludesObj
->nodesetval
->nodeTab
[i
]->content
;
956 // add includes to the end of list
958 // go to last element
959 struct string_list
* last_elem
= prep_includes
;
960 while (last_elem
->next
) last_elem
= last_elem
->next
;
961 // add string to last element if empty or create new last element and add it to that
962 if (last_elem
->str
) {
963 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
964 last_elem
= last_elem
->next
;
965 last_elem
->next
= NULL
;
967 replacechar(&content
);
968 last_elem
->str
= content
;
973 //preprocessorDefines
974 char *predefinesXpath
= mprintf(
975 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
976 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
978 XPathObject
predefinesObj(run_xpath(xpathCtx
, predefinesXpath
));
979 Free(predefinesXpath
);
981 xmlNodeSetPtr nodes
= predefinesObj
->nodesetval
;
983 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
984 const char* content
= (const char*)predefinesObj
->nodesetval
->nodeTab
[i
]->content
;
986 // add includes to the end of list
988 // go to last element
989 struct string_list
* last_elem
= prep_defines
;
990 while (last_elem
->next
) last_elem
= last_elem
->next
;
991 // add string to last element if empty or create new last element and add it to that
992 if (last_elem
->str
) {
993 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
994 last_elem
= last_elem
->next
;
995 last_elem
->next
= NULL
;
997 last_elem
->str
= mcopystr(content
);
1002 char *cxxCompilerXpath
= mprintf(
1003 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1004 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1006 XPathObject
cxxCompilerObj(run_xpath(xpathCtx
, cxxCompilerXpath
));
1007 Free(cxxCompilerXpath
);
1008 xmlNodeSetPtr nodes
= cxxCompilerObj
->nodesetval
;
1010 *cxxcompiler
= mcopystr((const char*)cxxCompilerObj
->nodesetval
->nodeTab
[0]->content
);
1014 char *optLevelXpath
= mprintf(
1015 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1016 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1018 XPathObject
optLevelObj(run_xpath(xpathCtx
, optLevelXpath
));
1019 Free(optLevelXpath
);
1020 xmlNodeSetPtr nodes
= optLevelObj
->nodesetval
;
1022 *optlevel
= mcopystr((const char*)optLevelObj
->nodesetval
->nodeTab
[0]->content
);
1026 char *optFlagsXpath
= mprintf(
1027 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1028 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1030 XPathObject
optFlagsObj(run_xpath(xpathCtx
, optFlagsXpath
));
1031 Free(optFlagsXpath
);
1032 xmlNodeSetPtr nodes
= optFlagsObj
->nodesetval
;
1034 *optflags
= mcopystr((const char*)optFlagsObj
->nodesetval
->nodeTab
[0]->content
);
1038 //SolarisSpecificLibraries
1039 char *solspeclibXpath
= mprintf(
1040 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1041 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1043 XPathObject
solspeclibObj(run_xpath(xpathCtx
, solspeclibXpath
));
1044 Free(solspeclibXpath
);
1046 xmlNodeSetPtr nodes
= solspeclibObj
->nodesetval
;
1048 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1049 char* content
= (char*)solspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1051 // add includes to the end of list
1053 // go to last element
1054 struct string_list
* last_elem
=solspeclibs
;
1055 while (last_elem
->next
) last_elem
= last_elem
->next
;
1056 // add string to last element if empty or create new last element and add it to that
1057 if (last_elem
->str
) {
1058 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1059 last_elem
= last_elem
->next
;
1060 last_elem
->next
= NULL
;
1062 replacechar(&content
);
1063 last_elem
->str
= content
;
1068 //Solaris8SpecificLibraries
1069 char *sol8speclibXpath
= mprintf(
1070 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1071 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1073 XPathObject
sol8speclibObj(run_xpath(xpathCtx
, sol8speclibXpath
));
1074 Free(sol8speclibXpath
);
1076 xmlNodeSetPtr nodes
= sol8speclibObj
->nodesetval
;
1078 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1079 char* content
= (char*)sol8speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1081 // add includes to the end of list
1083 // go to last element
1084 struct string_list
* last_elem
= sol8speclibs
;
1085 while (last_elem
->next
) last_elem
= last_elem
->next
;
1086 // add string to last element if empty or create new last element and add it to that
1087 if (last_elem
->str
) {
1088 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1089 last_elem
= last_elem
->next
;
1090 last_elem
->next
= NULL
;
1092 replacechar(&content
);
1093 last_elem
->str
= content
;
1098 //LinuxSpecificLibraries
1099 char *linuxspeclibXpath
= mprintf(
1100 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1101 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1103 XPathObject
linuxspeclibObj(run_xpath(xpathCtx
, linuxspeclibXpath
));
1104 Free(linuxspeclibXpath
);
1106 xmlNodeSetPtr nodes
= linuxspeclibObj
->nodesetval
;
1108 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1109 char* content
= (char*)linuxspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1111 // add includes to the end of list
1112 if (linuxspeclibs
) {
1113 // go to last element
1114 struct string_list
* last_elem
= linuxspeclibs
;
1115 while (last_elem
->next
) last_elem
= last_elem
->next
;
1116 // add string to last element if empty or create new last element and add it to that
1117 if (last_elem
->str
) {
1118 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1119 last_elem
= last_elem
->next
;
1120 last_elem
->next
= NULL
;
1122 replacechar(&content
);
1123 last_elem
->str
= content
;
1128 //FreeBSDSpecificLibraries
1129 char *freebsdspeclibXpath
= mprintf(
1130 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1131 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1133 XPathObject
freebsdspeclibObj(run_xpath(xpathCtx
, freebsdspeclibXpath
));
1134 Free(freebsdspeclibXpath
);
1136 xmlNodeSetPtr nodes
= freebsdspeclibObj
->nodesetval
;
1138 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1139 char* content
= (char*)freebsdspeclibObj
->nodesetval
->nodeTab
[i
]->content
;
1141 // add includes to the end of list
1142 if (freebsdspeclibs
) {
1143 // go to last element
1144 struct string_list
* last_elem
= freebsdspeclibs
;
1145 while (last_elem
->next
) last_elem
= last_elem
->next
;
1146 // add string to last element if empty or create new last element and add it to that
1147 if (last_elem
->str
) {
1148 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1149 last_elem
= last_elem
->next
;
1150 last_elem
->next
= NULL
;
1152 replacechar(&content
);
1153 last_elem
->str
= content
;
1158 //Win32SpecificLibraries
1159 char *win32speclibXpath
= mprintf(
1160 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1161 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1163 XPathObject
win32speclibObj(run_xpath(xpathCtx
, win32speclibXpath
));
1164 Free(win32speclibXpath
);
1166 xmlNodeSetPtr nodes
= win32speclibObj
->nodesetval
;
1168 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1169 char* content
= (char*)win32speclibObj
->nodesetval
->nodeTab
[i
]->content
;
1171 // add includes to the end of list
1172 if (win32speclibs
) {
1173 // go to last element
1174 struct string_list
* last_elem
= win32speclibs
;
1175 while (last_elem
->next
) last_elem
= last_elem
->next
;
1176 // add string to last element if empty or create new last element and add it to that
1177 if (last_elem
->str
) {
1178 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1179 last_elem
= last_elem
->next
;
1180 last_elem
->next
= NULL
;
1182 replacechar(&content
);
1183 last_elem
->str
= content
;
1190 char *ttcn3preproc
= mprintf(
1191 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1192 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1194 XPathObject
ttcn3preprocObj(run_xpath(xpathCtx
, ttcn3preproc
));
1196 xmlNodeSetPtr nodes
= ttcn3preprocObj
->nodesetval
;
1198 *ttcn3prep
= mcopystr((const char*)ttcn3preprocObj
->nodesetval
->nodeTab
[0]->content
);
1202 // additionalObjects
1203 char *additionalObjectsXpath
= mprintf(
1204 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1205 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1207 XPathObject
additionalObjectsObj(run_xpath(xpathCtx
, additionalObjectsXpath
));
1208 Free(additionalObjectsXpath
);
1210 xmlNodeSetPtr nodes
= additionalObjectsObj
->nodesetval
;
1212 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1213 char* content
= (char*)additionalObjectsObj
->nodesetval
->nodeTab
[i
]->content
;
1215 // add to the end of list
1216 if (additionalObjects
) {
1217 // go to last element
1218 struct string_list
* last_elem
= additionalObjects
;
1219 while (last_elem
->next
) last_elem
= last_elem
->next
;
1220 // add string to last element if empty or create new last element and add it to that
1221 if (last_elem
->str
) {
1222 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1223 last_elem
= last_elem
->next
;
1224 last_elem
->next
= NULL
;
1226 replacechar(&content
);
1227 last_elem
->str
= content
;
1233 char *linkerlibsXpath
= mprintf(
1234 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1235 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1237 XPathObject
linkerlibsObj(run_xpath(xpathCtx
, linkerlibsXpath
));
1238 Free(linkerlibsXpath
);
1240 xmlNodeSetPtr nodes
= linkerlibsObj
->nodesetval
;
1242 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1243 char* content
= (char*)linkerlibsObj
->nodesetval
->nodeTab
[i
]->content
;
1245 // add includes to the end of list
1247 // go to last element
1248 struct string_list
* last_elem
= linkerlibs
;
1249 while (last_elem
->next
) last_elem
= last_elem
->next
;
1250 // add string to last element if empty or create new last element and add it to that
1251 if (last_elem
->str
) {
1252 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1253 last_elem
= last_elem
->next
;
1254 last_elem
->next
= NULL
;
1256 replacechar(&content
);
1257 last_elem
->str
= content
;
1262 //linkerLibrarySearchPath
1263 char *linkerlibsearchXpath
= mprintf(
1264 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1265 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1267 XPathObject
linkerlibsearchObj(run_xpath(xpathCtx
, linkerlibsearchXpath
));
1268 Free(linkerlibsearchXpath
);
1270 xmlNodeSetPtr nodes
= linkerlibsearchObj
->nodesetval
;
1272 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1273 char* content
= (char*)linkerlibsearchObj
->nodesetval
->nodeTab
[i
]->content
;
1275 // add includes to the end of list
1276 if (linkerlibsearchp
) {
1277 // go to last element
1278 struct string_list
* last_elem
= linkerlibsearchp
;
1279 while (last_elem
->next
) last_elem
= last_elem
->next
;
1280 // add string to last element if empty or create new last element and add it to that
1281 if (last_elem
->str
) {
1282 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1283 last_elem
= last_elem
->next
;
1284 last_elem
->next
= NULL
;
1286 replacechar(&content
);
1287 last_elem
->str
= content
;
1292 if (generatorCommandOutput
&& local_argc
!= 0) { // only in case of top-level invocation
1293 char* generatorCommandXpath
= mprintf(
1294 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1295 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1297 XPathObject
generatorCommandObj(run_xpath(xpathCtx
, generatorCommandXpath
));
1298 Free(generatorCommandXpath
);
1299 autostring generatorCommand
;
1300 if (generatorCommandObj
->nodesetval
&& generatorCommandObj
->nodesetval
->nodeNr
> 0) {
1301 generatorCommand
= mcopystr((const char*)generatorCommandObj
->nodesetval
->nodeTab
[0]->content
);
1302 // run the command and capture the output
1303 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand
, (const char*)abs_tpd_name
);
1304 FILE* gc_fp
= popen(generatorCommand
, "r");
1306 ERROR("Could not execute command `%s'", (const char*)generatorCommand
);
1309 while (fgets(buff
, sizeof(buff
), gc_fp
)!=NULL
) {
1310 *generatorCommandOutput
= mputstr(*generatorCommandOutput
, buff
);
1317 if (target_placement_list
&& local_argc
!= 0) { // only in case of top-level invocation
1318 char* targetPlacementXpath
= mprintf(
1319 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1320 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1322 XPathObject
targetPlacementObj(run_xpath(xpathCtx
, targetPlacementXpath
));
1323 Free(targetPlacementXpath
);
1324 xmlNodeSetPtr nodes
= targetPlacementObj
->nodesetval
;
1325 const char* targetName
= NULL
;
1326 const char* targetPlacement
= NULL
;
1327 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1328 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1329 targetName
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1331 else if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
,"placement")) {
1332 targetPlacement
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1334 if (targetName
&& targetPlacement
) { // collected both
1335 if (target_placement_list
) {
1336 // go to last element
1337 struct string2_list
* last_elem
= target_placement_list
;
1338 while (last_elem
->next
) last_elem
= last_elem
->next
;
1339 // add strings to last element if empty or create new last element and add it to that
1340 if (last_elem
->str1
) {
1341 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
1342 last_elem
= last_elem
->next
;
1343 last_elem
->next
= NULL
;
1345 last_elem
->str1
= mcopystr(targetName
);
1346 last_elem
->str2
= mcopystr(targetPlacement
);
1348 targetName
= targetPlacement
= NULL
; // forget both
1353 // Referenced projects
1355 XPathObject
subprojects(run_xpath(xpathCtx
,
1356 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::*"));
1357 xmlNodeSetPtr nodes
= subprojects
->nodesetval
;
1358 const char *name
= NULL
, *projectLocationURI
= NULL
;
1359 if (nodes
) for (int i
= 0; i
< nodes
->nodeNr
; ++i
) {
1360 // FIXME: this assumes every ReferencedProject has name and URI.
1361 // This is not necessarily so if the referenced project was closed
1362 // when the project was exported to TPD.
1363 // Luckily, the name from the closed project will be overwritten
1364 // by the name from the next ReferencedProject. However, if some pervert
1365 // changes the next ReferencedProject to have the projectLocationURI
1366 // as the first attribute, it will be joined to the name
1367 // of the previous, closed, ReferencedProject.
1368 if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
, "name")) {
1369 name
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1371 else if (!strcmp((const char*)nodes
->nodeTab
[i
]->name
,"projectLocationURI")) {
1372 projectLocationURI
= (const char*)nodes
->nodeTab
[i
]->children
->content
;
1375 if (name
&& projectLocationURI
) { // collected both
1376 // see if there is a specified configuration for the project
1377 const char *my_actcfg
= NULL
;
1378 autostring
req_xpath(mprintf(
1379 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1380 "/ProjectProperties/ConfigurationRequirements/configurationRequirement"
1381 "/projectName[text()='%s']"
1382 // Up to this point, we selected the projectName node which contains
1383 // the name of the subproject. But we want its sibling.
1384 // So we go up one and down the other path.
1385 "/parent::*/rerquiredConfiguration/text()",
1386 //Yes, it's rerquiredConfiguration; the Designer misspells it :(
1388 XPathObject
reqcfgObj(run_xpath(xpathCtx
, req_xpath
));
1389 if (reqcfgObj
->nodesetval
&& reqcfgObj
->nodesetval
->nodeNr
== 1) {
1390 my_actcfg
= (const char*)reqcfgObj
->nodesetval
->nodeTab
[0]->content
;
1394 char *my_args
[] = { NULL
};
1395 char **my_argv
= my_args
+ 0;
1397 boolean my_gflag
= *p_gflag
, my_aflag
= *p_aflag
, my_cflag
= *p_cflag
, // pass down
1398 my_Rflag
= *p_Rflag
, my_Pflag
= *p_Pflag
,
1399 my_sflag
= 0, my_Lflag
= 0, my_lflag
= 0, my_mflag
= 0, my_csflag
= 0,
1400 my_quflag
= 0, my_dsflag
= 0, my_dbflag
= 0, my_drflag
= 0,
1401 my_dtflag
= 0, my_dxflag
= 0, my_djflag
= 0, my_fxflag
= 0, my_doflag
= 0,
1402 my_gfflag
= 0, my_lnflag
= 0, my_isflag
= 0, my_asflag
= 0,
1403 my_swflag
= 0, my_Yflag
= 0;
1405 char *my_ets
= NULL
;
1407 autostring
abs_projectLocationURI(
1408 compose_path_name(abs_tpd_dir
, projectLocationURI
));
1410 char* sub_proj_abs_work_dir
= NULL
;
1411 tpd_result success
= process_tpd_internal((const char*)abs_projectLocationURI
,
1412 my_actcfg
, file_list_path
, &my_argc
, &my_argv
, &my_optind
, &my_ets
,
1413 &my_gflag
, &my_sflag
, &my_cflag
, &my_aflag
, preprocess
, &my_Rflag
, &my_lflag
,
1414 &my_mflag
, &my_Pflag
, &my_Lflag
, recursive
, force_overwrite
, gen_only_top_level
, NULL
, &sub_proj_abs_work_dir
,
1415 sub_project_dirs
, program_name
, prj_graph_fp
, create_symlink_list
, ttcn3_prep_includes
, ttcn3_prep_defines
, prep_includes
, prep_defines
, &my_csflag
,
1416 &my_quflag
, &my_dsflag
, cxxcompiler
, optlevel
, optflags
, &my_dbflag
, &my_drflag
,
1417 &my_dtflag
, &my_dxflag
, &my_djflag
, &my_fxflag
, &my_doflag
,
1418 &my_gfflag
, &my_lnflag
, &my_isflag
, &my_asflag
, &my_swflag
, &my_Yflag
, solspeclibs
, sol8speclibs
, linuxspeclibs
, freebsdspeclibs
, win32speclibs
,
1419 ttcn3prep
, linkerlibs
, additionalObjects
, linkerlibsearchp
, Vflag
, FALSE
, NULL
, NULL
, prefix_workdir
, run_command_list
, seen_tpd_files
);
1420 autostring
sub_proj_abs_work_dir_as(sub_proj_abs_work_dir
); // ?!
1422 if (success
== TPD_SUCCESS
) {
1424 if (recursive
) { // call ttcn3_makefilegen on referenced project's tpd file
1425 // -r is not needed any more because top level process traverses all projects recursively
1426 expstring_t command
= mprintf("%s -cVD", program_name
);
1427 if (force_overwrite
) command
= mputc(command
, 'f');
1428 if (prefix_workdir
) command
= mputc(command
, 'W');
1429 if (*p_gflag
) command
= mputc(command
, 'g');
1430 if (*p_sflag
) command
= mputc(command
, 's');
1431 if (*p_aflag
) command
= mputc(command
, 'a');
1432 if (*p_Rflag
) command
= mputc(command
, 'R');
1433 if (*p_lflag
) command
= mputc(command
, 'l');
1434 if (*p_mflag
) command
= mputc(command
, 'm');
1435 command
= mputstr(command
, " -t ");
1436 command
= mputstr(command
, (const char*)abs_projectLocationURI
);
1438 command
= mputstr(command
, " -b ");
1439 command
= mputstr(command
, my_actcfg
);
1442 autostring
sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI
));
1443 const char * sub_proj_effective_work_dir
= sub_proj_abs_work_dir
? sub_proj_abs_work_dir
: (const char*)sub_tpd_dir
;
1444 if (!gen_only_top_level
) {
1445 if (run_command_list
) {
1446 // go to last element
1447 struct string2_list
* last_elem
= run_command_list
;
1448 while (last_elem
->next
) last_elem
= last_elem
->next
;
1449 // add strings to last element if empty or create new last element and add it to that
1450 if (last_elem
->str1
|| last_elem
->str2
) {
1451 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
1452 last_elem
= last_elem
->next
;
1453 last_elem
->next
= NULL
;
1455 last_elem
->str1
= mcopystr(sub_proj_effective_work_dir
);
1456 last_elem
->str2
= command
;
1458 ERROR("Internal error: cannot add command to list");
1461 // add working dir to the end of list
1462 if (sub_project_dirs
) {
1463 // go to last element
1464 struct string_list
* last_elem
= sub_project_dirs
;
1465 while (last_elem
->next
) last_elem
= last_elem
->next
;
1466 // add string to last element if empty or create new last element and add it to that
1467 if (last_elem
->str
) {
1468 last_elem
->next
= (struct string_list
*)Malloc(sizeof(struct string_list
));
1469 last_elem
= last_elem
->next
;
1470 last_elem
->next
= NULL
;
1472 autostring
cwd_as(get_working_dir());
1473 last_elem
->str
= (*p_aflag
) ? mcopystr(sub_proj_effective_work_dir
) : get_relative_dir(sub_proj_effective_work_dir
, (const char*)cwd_as
);
1477 for (int z
= 0; z
< my_argc
; ++z
) {
1479 // central storage, keep in separate container
1480 base_files
.add(my_argv
[z
]); // string was allocated with new
1483 const cstring
tmp(my_argv
[z
]);
1484 if (!files
.has_key(tmp
)){
1485 files
.add(tmp
, my_argv
[z
]);
1492 Free(my_argv
); // free the array; we keep the pointers
1495 else if (success
== TPD_FAILED
) {
1496 ERROR("Failed to process %s", (const char*)abs_projectLocationURI
);
1498 // else TPD_SKIPPED, keep quiet
1500 name
= projectLocationURI
= NULL
; // forget both
1502 } // next referenced project
1506 if (get_path_status(output_file
) == PS_DIRECTORY
) {
1507 // points to existing dir; use as-is
1509 else { // we assume it points to a file: not our problem
1514 // (argc - optind) is the number of non-option arguments (assumed to be files)
1515 // given on the command line.
1516 int new_argc
= local_argc
- local_optind
+ files
.size() + base_files
.size();
1517 char ** new_argv
= (char**)Malloc(sizeof(char*) * new_argc
);
1521 // First, copy the filenames gathered from the TPD
1523 // We symlink the files into the working directory
1524 // and pass only the filename to the makefile generator
1525 for (int nf
= files
.size(); n
< nf
; ++n
) {
1526 const char *fn
= files
.get_nth_elem(n
); // relativeURI to the TPD location
1527 autostring
dir_n (get_dir_from_path (fn
));
1528 autostring
file_n(get_file_from_path(fn
));
1529 autostring
rel_n (get_absolute_dir(dir_n
, abs_tpd_dir
));
1530 autostring
abs_n (compose_path_name(rel_n
, file_n
));
1532 if (local_argc
== 0) {
1533 // We are being invoked recursively, for a referenced TPD.
1534 // Do not symlink; just return absolute paths to the files.
1537 // compose with workdir
1538 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
1540 // it's an absolute path, copy verbatim
1541 new_argv
[n
] = mcopystr(fn
); // fn will be destroyed, pass a copy
1544 else { // relative path
1546 // compose with workdir
1547 new_argv
[n
] = compose_path_name(abs_workdir
, file_n
);
1548 // Do not call file_n.extract() : the composed path will be returned,
1549 // its component will need to be deallocated here.
1552 // compose with tpd dir
1553 new_argv
[n
] = const_cast<char*>(abs_n
.extract());
1557 else { // we are processing the top-level TPD
1560 int fd
= open(abs_n
, O_RDONLY
);
1561 if (fd
>= 0) { // successfully opened
1564 file_n
= compose_path_name(output_file
, file_n
);
1566 //TODO ! compose with output_file
1567 // save into list: add symlink data to the end of list
1568 if (create_symlink_list
) {
1569 // go to last element
1570 struct string2_list
* last_elem
= create_symlink_list
;
1571 while (last_elem
->next
) last_elem
= last_elem
->next
;
1572 // add strings to last element if empty or create new last element and add it to that
1573 if (last_elem
->str1
) {
1574 last_elem
->next
= (struct string2_list
*)Malloc(sizeof(struct string2_list
));
1575 last_elem
= last_elem
->next
;
1576 last_elem
->next
= NULL
;
1578 last_elem
->str1
= mcopystr(abs_n
);
1579 last_elem
->str2
= mcopystr(file_n
);
1583 ERROR("%s does not exist", (const char*)abs_n
);
1589 puts((const char *)abs_n
);
1591 autostring
dir_part(get_dir_from_path(abs_n
));
1592 autostring
file_part(get_file_from_path(abs_n
));
1593 autostring
rel_dir_part(get_relative_dir((const char *)dir_part
, file_list_path
? file_list_path
: (const char *)abs_tpd_dir
));
1594 autostring
rel_dir_file_part(compose_path_name((const char *)rel_dir_part
, (const char *)file_part
));
1595 puts((const char *)rel_dir_file_part
);
1598 new_argv
[n
] = const_cast<char *>(file_n
.extract());
1601 // Print the TPD too.
1603 autostring
dir_part(get_dir_from_path(p_tpd_name
));
1604 autostring
file_part(get_file_from_path(p_tpd_name
));
1606 puts((const char *)abs_tpd_name
);
1608 autostring
rel_dir_part(get_relative_dir(dir_part
, file_list_path
? file_list_path
: abs_tpd_dir
));
1609 autostring
rel_dir_file_part(compose_path_name(rel_dir_part
, file_part
));
1610 const char *rel_tpd_name
= (const char *)rel_dir_file_part
;
1615 // base_files from referenced projects
1616 for (size_t bf
= 0, bs
= base_files
.size(); bf
< bs
; ++bf
, ++n
) {
1617 new_argv
[n
] = base_files
[bf
];
1619 base_files
.clear(); // string ownership transfered
1621 // Then, copy the filenames from the command line.
1622 for (int a
= *p_optind
; a
< *p_argc
; ++a
, ++n
) {
1623 // String may be from main's argv; copy to the heap.
1624 new_argv
[n
] = mcopystr((*p_argv
)[a
]);
1627 if (local_argc
> 0) { // it is the outermost call
1628 clear_seen_tpd_files(seen_tpd_files
);
1636 for (size_t i
= 0, e
= files
.size(); i
< e
; ++i
) {
1637 Free(const_cast<char*>(files
.get_nth_elem(i
)));
1641 for (size_t i
= 0, e
= folders
.size(); i
< e
; ++i
) {
1642 Free(const_cast<char*>(folders
.get_nth_elem(i
)));
1646 excluded_files
.clear();
1647 excluded_folders
.clear();