Sync with 5.2.0
[deliverable/titan.core.git] / compiler2 / xpather.cc
CommitLineData
970ed795
EL
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///////////////////////////////////////////////////////////////////////////////
8#include "xpather.h"
9
10#include <string.h>
11#include <assert.h>
12#include <unistd.h>
13#include <limits.h>
14#include <errno.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <fcntl.h>
18#include <string>
19
20#include <libxml/parser.h>
21#include <libxml/tree.h>
22#include <libxml/xpath.h>
23
24#define LIBXML_SCHEMAS_ENABLED
25#include <libxml/xmlschemastypes.h>
26
27#include "../common/memory.h"
28#include "vector.hh"
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 :(
31#include "map.hh"
af710487 32#include "ProjectGenHelper.hh"
970ed795 33#include "../common/path.h"
af710487 34#include "ttcn3/ttcn3_preparser.h"
35#include "asn1/asn1_preparser.h"
970ed795
EL
36
37// in makefile.c
38void ERROR (const char *fmt, ...);
39void WARNING(const char *fmt, ...);
40void NOTIFY (const char *fmt, ...);
41void DEBUG (const char *fmt, ...);
42
43// for vector and map
44void fatal_error(const char * filename, int lineno, const char * fmt, ...)
45__attribute__ ((__format__ (__printf__, 3, 4), __noreturn__));
46
47void fatal_error(const char * filename, int lineno, const char * fmt, ...)
48{
49 fputs(filename, stderr);
50 fprintf(stderr, ":%d: ", lineno);
51 va_list va;
52 va_start(va, fmt);
53 vfprintf(stderr, fmt, va);
54 va_end(va);
55 abort();
56}
57
af710487 58ProjectGenHelper& projGenHelper = ProjectGenHelper::Instance();
59
970ed795
EL
60/// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
61xmlXPathObjectPtr run_xpath(xmlXPathContextPtr xpathCtx, const char *xpathExpr)
62{
63 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(
64 (const xmlChar *)xpathExpr, xpathCtx);
65 if(xpathObj == NULL) {
66 fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
67 return 0;
68 }
69
70 return xpathObj;
71}
72
73// RAII classes
74
75class XmlDoc {
76public:
77 explicit XmlDoc(xmlDocPtr p) : doc_(p) {}
78 ~XmlDoc() {
79 if (doc_ != NULL) xmlFreeDoc(doc_);
80 }
81 operator xmlDocPtr() const { return doc_; }
82private:
83 xmlDocPtr doc_;
84};
85
86class XPathContext {
87public:
88 explicit XPathContext(xmlXPathContextPtr c) : ctx_(c) {}
89 ~XPathContext() {
90 if (ctx_ != NULL) xmlXPathFreeContext(ctx_);
91 }
92 operator xmlXPathContextPtr() const { return ctx_; }
93private:
94 xmlXPathContextPtr ctx_;
95};
96
97class XPathObject {
98public:
99 explicit XPathObject(xmlXPathObjectPtr o) : xpo_(o) {}
100 ~XPathObject() {
101 if (xpo_ != NULL) xmlXPathFreeObject(xpo_);
102 }
103 operator xmlXPathObjectPtr() const { return xpo_; }
104 xmlXPathObjectPtr operator->() const { return xpo_; }
105private:
106 xmlXPathObjectPtr xpo_;
107};
108
109//------------------------------------------------------------------
110/// compare-by-content wrapper of a plain C string
111struct cstring {
112 explicit cstring(const char *s) : str(s) {}
113 void destroy() const;
114 operator const char*() const { return str; }
115protected:
116 const char *str;
117 friend boolean operator<(const cstring& l, const cstring& r);
118 friend boolean operator==(const cstring& l, const cstring& r);
119};
120
121void cstring::destroy() const {
122 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
123}
124
125boolean operator<(const cstring& l, const cstring& r) {
126 return strcmp(l.str, r.str) < 0;
127}
128
129boolean operator==(const cstring& l, const cstring& r) {
130 return strcmp(l.str, r.str) == 0;
131}
132
133/// RAII for C string
134struct autostring : public cstring {
135 /// Constructor; takes over ownership
136 explicit autostring(const char *s = 0) : cstring(s) {}
137 ~autostring() {
138 // He who can destroy a thing, controls that thing -- Paul Muad'Dib
139 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
140 }
141 /// %Assignment; takes over ownership
142 const autostring& operator=(const char *s) {
143 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
144 str = s;
145 return *this;
146 }
147 /// Relinquish ownership
148 const char *extract() {
149 const char *retval = str;
150 str = 0;
151 return retval;
152 }
153private:
154 autostring(const autostring&);
155 autostring& operator=(const autostring&);
156};
157
158
159bool validate_tpd(const XmlDoc& xml_doc, const char* tpd_file_name, const char* xsd_file_name)
160{
161 xmlLineNumbersDefault(1);
162
163 xmlSchemaParserCtxtPtr ctxt = xmlSchemaNewParserCtxt(xsd_file_name);
164 if (ctxt==NULL) {
165 ERROR("Unable to create xsd context for xsd file `%s'", xsd_file_name);
166 return false;
167 }
168 xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc)fprintf, (xmlSchemaValidityWarningFunc)fprintf, stderr);
169
170 xmlSchemaPtr schema = xmlSchemaParse(ctxt);
171 if (schema==NULL) {
172 ERROR("Unable to parse xsd file `%s'", xsd_file_name);
173 xmlSchemaFreeParserCtxt(ctxt);
174 return false;
175 }
176
177 xmlSchemaValidCtxtPtr xsd = xmlSchemaNewValidCtxt(schema);
178 if (xsd==NULL) {
179 ERROR("Schema validation error for xsd file `%s'", xsd_file_name);
180 xmlSchemaFree(schema);
181 xmlSchemaFreeParserCtxt(ctxt);
182 return false;
183 }
184 xmlSchemaSetValidErrors(xsd, (xmlSchemaValidityErrorFunc) fprintf, (xmlSchemaValidityWarningFunc) fprintf, stderr);
185
186 int ret = xmlSchemaValidateDoc(xsd, xml_doc);
187
188 xmlSchemaFreeValidCtxt(xsd);
189 xmlSchemaFree(schema);
190 xmlSchemaFreeParserCtxt(ctxt);
191 xmlSchemaCleanupTypes();
192
193 if (ret==0) {
194 return true; // successful validation
195 } else if (ret>0) {
196 ERROR("TPD file `%s' is invalid according to schema `%s'", tpd_file_name, xsd_file_name);
197 return false;
198 } else {
199 ERROR("TPD validation of `%s' generated an internal error in libxml2", tpd_file_name);
200 return false;
201 }
202}
203
204/** Extract a boolean value from the XML, if it exists otherwise flag is unchanged
205 *
206 * @param xpathCtx XPath context object
207 * @param actcfg name of the active configuration
208 * @param option name of the value
209 * @param flag pointer to the variable to receive the value
210 */
211void xsdbool2boolean(const XPathContext& xpathCtx, const char *actcfg,
212 const char *option, boolean* flag)
213{
214 char *xpath = mprintf(
215 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
216 "/ProjectProperties/MakefileSettings/%s[text()='true']",
217 actcfg, option);
218 XPathObject xpathObj(run_xpath(xpathCtx, xpath));
219 Free(xpath);
220
221 if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
222 *flag = TRUE;
223 }
224}
225
af710487 226extern "C" string_list* getExternalLibs(const char* projName)
227{
228 if (!projGenHelper.getZflag()) return NULL;
229 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
230 if (!proj) return NULL;
231
232 std::vector<const char*> externalLibs;
233 projGenHelper.getExternalLibs(externalLibs);
234
235 if (0 == externalLibs.size()) return NULL;
236
237 struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
238 struct string_list* last_elem = head;
239 struct string_list* tail = head;
240
241 for (size_t i = 0; i < externalLibs.size(); ++i) {
242 tail = last_elem;
243 last_elem->str = mcopystr(externalLibs[i]);
244 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
245 last_elem = last_elem->next;
246 }
247 Free(last_elem);
248 tail->next = NULL;
249 return head;
250}
251
252extern "C" string_list* getExternalLibPathes(const char* projName)
253{
254 if (!projGenHelper.getZflag()) return NULL;
255 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
256 if (!proj) return NULL;
257
258 std::vector<const char*> externalLibs;
259 projGenHelper.getExternalLibSearchPathes(externalLibs);
260
261 if (0 == externalLibs.size()) return NULL;
262
263 struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
264 struct string_list* last_elem = head;
265 struct string_list* tail = head;
266
267 for (size_t i = 0; i < externalLibs.size(); ++i) {
268 tail = last_elem;
269 last_elem->str = mcopystr(externalLibs[i]);
270 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
271 last_elem = last_elem->next;
272 }
273 Free(last_elem);
274 tail->next = NULL;
275 return head;
276}
277
278extern "C" string_list* getRefWorkingDirs(const char* projName)
279{
280 if (!projGenHelper.getZflag()) return NULL;
281 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
282 if (!proj) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
283
284 struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list));
285 struct string_list* last_elem = head;
286 struct string_list* tail = head;
287 last_elem->str = NULL;
288 last_elem->next = NULL;
289 for (size_t i = 0; i < proj->numOfRefProjWorkingDirs(); ++i) {
290 tail = last_elem;
291 last_elem->str = mcopystr(proj->getRefProjWorkingDir(i).c_str());
292 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
293 last_elem = last_elem->next;
294 }
295 Free(last_elem);
296 tail->next = NULL;
297 return head;
298}
299
300extern "C" string2_list* getLinkerLibs(const char* projName)
301{
302
303 if (!projGenHelper.getZflag()) return NULL;
304 if (1 == projGenHelper.numOfProjects() || 0 == projGenHelper.numOfLibs()){
305 return NULL; //no library
306 }
307 ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
308 if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
309
310 struct string2_list* head = (struct string2_list*)Malloc(sizeof(struct string2_list));
311 struct string2_list* last_elem = head;
312 struct string2_list* tail = head;
313 last_elem->next = NULL;
314 last_elem->str1 = NULL;
315 last_elem->str2 = NULL;
316 for (std::map<std::string, ProjectDescriptor>::const_iterator it = projGenHelper.getHead();
317 it != projGenHelper.getEnd(); ++it) {
318 if ((it->second).isLibrary()) {
319 if (!(it->second).getLinkingStrategy() &&
320 !projLib->hasLinkerLibTo((it->second).getProjectName())) { // static linked library
321 continue;
322 }
323 std::string relPath = projLib->setRelativePathTo((it->second).getProjectAbsWorkingDir());
324 if (relPath == std::string(".")) {
325 continue; // the relpath shows to itself
326 }
327 tail = last_elem;
328 last_elem->str1 = mcopystr(relPath.c_str());
329 last_elem->str2 = mcopystr((it->second).getTargetExecName().c_str());
330 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
331 last_elem = last_elem->next;
332 }
333 }
334 tail->next = NULL;
335 Free(last_elem);
336
337 if (head->str1 && head->str2)
338 return head;
339 else
340 return NULL;
341}
342
343extern "C" const char* getLibFromProject(const char* projName)
344{
345 if (!projGenHelper.getZflag()) return NULL;
346 ProjectDescriptor* lib = projGenHelper.getTargetOfProject(projName);
347 if (lib) return lib->getTargetExecName().c_str();
348 return NULL;
349}
350
351extern "C" void erase_libs() {
352 projGenHelper.cleanUp();
353}
354
355extern "C" void print_libs() {
356 projGenHelper.print();
357}
358
359
360extern "C" boolean hasSubProject(const char* projName) {
361 if (!projGenHelper.getZflag()) return FALSE;
362 if (projGenHelper.getHflag())
363 return static_cast<boolean>(projGenHelper.hasReferencedProject());
364 else if(std::string(projName) == projGenHelper.getToplevelProjectName())
365 return static_cast<boolean>(projGenHelper.hasReferencedProject());
366 else
367 return FALSE;
368}
369
370extern "C" boolean hasExternalLibrary(const char* libName, const char* projName) {
371 if (!projGenHelper.getZflag()) return FALSE;
372 ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
373 if (projLib && projLib->hasLinkerLib(libName))
374 return TRUE;
375 else
376 return FALSE;
377}
378
379extern "C" boolean isTopLevelExecutable(const char* projName) {
380 if (!projGenHelper.getZflag()) return false;
381 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
382 if (projGenHelper.getToplevelProjectName() != std::string(projName)) return FALSE;
383 if (proj && proj->isLibrary())
384 return FALSE;
385 else
386 return TRUE;
387}
388
389extern "C" boolean isDynamicLibrary(const char* key) {
390 if (!projGenHelper.getZflag()) return false;
391 ProjectDescriptor* proj = projGenHelper.getProjectDescriptor(key);
392 if (proj) return proj->getLinkingStrategy();
393 FATAL_ERROR("Library \"%s\" was not found", key);
394 return false;
395}
396
397extern "C" const char* getTPDFileName(const char* projName) {
398 if (!projGenHelper.getZflag()) return NULL;
399 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
400 if (proj) return proj->getTPDFileName().c_str();
401 FATAL_ERROR("TPD file name to project \"%s\" was not found", projName);
402}
403
404extern "C" const char* getPathToRootDir(const char* projName) {
405 if (!projGenHelper.getZflag()) return NULL;
406 ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName);
407 const char* rootDir = projGenHelper.getRootDirOS(projName).c_str();
408 if (proj && rootDir) {
409 return rootDir;
410 }
411 FATAL_ERROR("Project \"%s\": no relative path was found to top directory at OS level.", projName);
412}
413
414extern "C" const char* findLibraryPath(const char* libraryName, const char* projName)
415{
416 if (!projGenHelper.getZflag()) return NULL;
417 ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
418 if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
419 ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName);
420 if (!libLib) return NULL;
421 std::string str = projLib->setRelativePathTo(libLib->getProjectAbsWorkingDir());
422 size_t refIndex = projLib->getLibSearchPathIndex(libLib->getProjectName());
423 if (refIndex > projLib->numOfLibSearchPaths()) return NULL;
424 projLib->setLibSearchPath(refIndex, str);
425 return projLib->getLibSearchPath(libLib->getProjectName());
426}
427
428extern "C" const char* findLibraryName(const char* libraryName, const char* projName)
429{
430 if (!projGenHelper.getZflag()) return NULL;
431 ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName);
432 if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName);
433 ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName);
434 if (!libLib) return NULL;
435 for (size_t i = 0; i < projLib->numOfReferencedProjects(); ++i) {
436 const std:: string refProjName = projLib->getReferencedProject(i);
437 ProjectDescriptor* refLib = projGenHelper.getTargetOfProject(refProjName.c_str());
438 if (refLib->getTargetExecName() == std::string(libraryName))
439 return libraryName;
440 }
441 return NULL;
442}
443
444extern "C" boolean isTtcn3ModuleInLibrary(const char* moduleName)
445{
446 if (!projGenHelper.getZflag()) return FALSE;
447 return (boolean)projGenHelper.isTtcn3ModuleInLibrary(moduleName);
448}
449
450extern "C" boolean isAsn1ModuleInLibrary(const char* moduleName)
451{
452 if (!projGenHelper.getZflag()) return FALSE;
453 return (boolean)projGenHelper.isAsn1ModuleInLibrary(moduleName);
454}
455
456extern "C" boolean isSourceFileInLibrary(const char* fileName)
457{
458 if (!projGenHelper.getZflag()) return FALSE;
459 return (boolean)projGenHelper.isSourceFileInLibrary(fileName);
460}
461
462extern "C" boolean isHeaderFileInLibrary(const char* fileName)
463{
464 if (!projGenHelper.getZflag()) return FALSE;
465 return (boolean)projGenHelper.isHeaderFileInLibrary(fileName);
466}
467
468extern "C" boolean isTtcnPPFileInLibrary(const char* fileName)
469{
470 if (!projGenHelper.getZflag()) return FALSE;
471 return (boolean)projGenHelper.isTtcnPPFileInLibrary(fileName);
472}
473
474
475extern "C" boolean buildObjects(const char* projName, boolean add_referenced)
476{
477 if (!projGenHelper.getZflag()) return FALSE;
478 if (projGenHelper.getHflag()) return FALSE;
479 if (add_referenced) return FALSE;
480 ProjectDescriptor* desc =projGenHelper.getTargetOfProject(projName);
481 if (desc && desc->isLibrary()) return FALSE;
482 return TRUE;
483}
484
485void append_to_library_list (const char* prjName,
486 const XPathContext& xpathCtx,
487 const char *actcfg)
488{
489 if (!projGenHelper.getZflag()) return;
490
491 char *exeXpath = mprintf(
492 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
493 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
494 actcfg);
495 XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
496 Free(exeXpath);
497 std::string lib_name;
498 if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
499 const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
500 autostring target_exe_dir(get_dir_from_path(target_executable));
501 autostring target_exe_file(get_file_from_path(target_executable));
502 lib_name = target_exe_file;
503 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(prjName);
504 if (projDesc) {
505 projDesc->setTargetExecName(lib_name.c_str());
506 }
507 }
508}
509
970ed795
EL
510// data structures and functions to manage excluded folders/files
511
af710487 512map<cstring, const char> excluded_files;
970ed795 513
af710487 514boolean is_excluded_file(const cstring& path, const char* project) {
515 if (!excluded_files.has_key(path)) return false;
516 const char* proj = excluded_files[path];
517 if (0 == strcmp(project, proj)) return true;
518 return false;
970ed795
EL
519}
520
521vector<const char> excluded_folders;
522
523// Unfortunately, when "docs" is excluded, we need to drop
524// files in "docs/", "docs/pdf/", "docs/txt/", "docs/txt/old/" etc;
525// so it's not as simple as using a map :(
526
527/** Checks whether a file is under an excluded folder
528 *
529 * @param path (relative) path of the file
530 * @return true if file is excluded, false otherwise
531 */
532boolean is_excluded_folder(const char *path) {
533 boolean answer = FALSE;
534 size_t pathlen = strlen(path);
535
536 for (size_t i = 0, end = excluded_folders.size(); i < end; ++i) {
537 const char *xdir = excluded_folders[i];
538 size_t xdlen = strlen(xdir);
539 if (pathlen > xdlen && path[xdlen] == '/') {
540 // we may have a winner
541 if ((answer = !strncmp(path, xdir, xdlen))) break;
542 }
543 }
544 return answer;
545}
546
547// How do you treat a raw info? You cook it, of course!
548// Returns a newly allocated string.
549char *cook(const char *raw, const map<cstring, const char>& path_vars)
550{
551 const char *slash = strchr(raw, '/');
552 if (!slash) { // Pretend that the slash is at the end of the string.
553 slash = raw + strlen(raw);
554 }
555
556 // Assume that a path variable reference is the first (or only) component
557 // of the path: ROOT in "ROOT/etc/issue".
558 autostring prefix(mcopystrn(raw, slash - raw));
559 if (path_vars.has_key(prefix)) {
560 char *cooked = mcopystr(path_vars[prefix]);
561 bool ends_with_slash = cooked[strlen(cooked)-1] == '/';
562 if (ends_with_slash && *slash == '/') {
563 // Avoid paths with two slashes at the start; Cygwin thinks it's UNC
564 ++slash;
565 }
566 // If there was no '/' (only the path variable reference e.g "ROOT")
567 // then slash points to a null byte and the mputstr is a no-op.
568 cooked = mputstr(cooked, slash);
569 return cooked;
570 }
571
572 // If the path variable could not be substituted,
573 // return (a copy of) the original.
574 return mcopystr(raw);
575}
576
577void replacechar(char** content) {
578
579 std::string s= *content;
580 size_t found = 0;
581 while ((found = s.find('['))!= std::string::npos){
582 s.replace(found,1, "${");
583 }
584 while ((found = s.find(']')) != std::string::npos){
585 s.replace(found,1, "}");
586 }
587 *content = mcopystr(s.c_str());
588}
589
590static void clear_seen_tpd_files(map<cstring, int>& seen_tpd_files) {
591 for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
592 const cstring& key = seen_tpd_files.get_nth_key(i);
593 int *elem = seen_tpd_files.get_nth_elem(i);
594 key.destroy();
595 delete elem;
596 }
597 seen_tpd_files.clear();
598}
599
af710487 600const char* get_act_config(struct string2_list* cfg, const char* project_name) {
601 while (cfg && cfg->str1 && project_name) {
602 if (!strcmp(cfg->str1, project_name)) return cfg->str2;
603 cfg = cfg->next;
604 }
605 return NULL;
606}
607
970ed795
EL
608static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg,
609 const char *file_list_path, int *p_argc, char ***p_argv,
af710487 610 int *p_optind, char **p_ets_name, char **p_project_name,
970ed795
EL
611 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
612 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
613 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
614 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
615 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
af710487 616 struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
617 struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag,
618 char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag,
619 boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
970ed795
EL
620 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
621 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
622 struct string_list* linkerlibs, struct string_list* additionalObjects, struct string_list* linkerlibsearchp, boolean Vflag, boolean Dflag,
af710487 623 boolean *p_Zflag, boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
624 struct string2_list* run_command_list, map<cstring, int>& seen_tpd_files, struct string2_list* required_configs);
970ed795
EL
625
626extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
627 const char *file_list_path, int *p_argc, char ***p_argv,
af710487 628 int *p_optind, char **p_ets_name, char **p_project_name,
970ed795
EL
629 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
630 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
631 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
632 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
633 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
af710487 634 struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
635 struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag,
636 char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag,
637 boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
970ed795
EL
638 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
639 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
af710487 640 string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag,
641 boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
642 struct string2_list* run_command_list, struct string2_list* required_configs) {
970ed795
EL
643
644 map<cstring, int> seen_tpd_files;
af710487 645 projGenHelper.setZflag(*p_Zflag);
646 projGenHelper.setWflag(prefix_workdir);
647 projGenHelper.setHflag(*p_Hflag);
970ed795
EL
648
649 tpd_result success = process_tpd_internal(p_tpd_name,
af710487 650 actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, p_project_name,
970ed795
EL
651 p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
652 p_Rflag, p_lflag, p_mflag, p_Pflag,
653 p_Lflag, recursive, force_overwrite, gen_only_top_level,
654 output_file, abs_work_dir_p, sub_project_dirs,
655 program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes,
af710487 656 ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines,
657 prep_undefines, p_csflag, p_quflag, p_dsflag, cxxcompiler,
970ed795
EL
658 optlevel, optflags, p_dbflag, p_drflag, p_dtflag, p_dxflag, p_djflag,
659 p_fxflag, p_doflag, p_gfflag, p_lnflag, p_isflag,
660 p_asflag, p_swflag, p_Yflag, solspeclibs, sol8speclibs,
661 linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep,
af710487 662 linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag, p_Zflag,
663 p_Hflag, generatorCommandOutput, target_placement_list, prefix_workdir,
664 run_command_list, seen_tpd_files, required_configs);
665
666 if (TPD_FAILED == success) exit(EXIT_FAILURE);
667
668 if (false == projGenHelper.sanityCheck()) {
669 fprintf (stderr, "makefilegen exits\n");
670 exit(EXIT_FAILURE);
671 }
672
673 projGenHelper.generateRefProjectWorkingDirsTo(*p_project_name);
970ed795
EL
674
675 for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
676 const cstring& key = seen_tpd_files.get_nth_key(i);
677 int *elem = seen_tpd_files.get_nth_elem(i);
678 key.destroy();
679 delete elem;
680 }
681 seen_tpd_files.clear();
682
683 return success;
684}
685
686// optind is the index of the next element of argv to be processed.
687// Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
688// seen already, or TPD_FAILED.
689//
690// Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
691// (argv[], ets_name, other_files[], output_file) are allocated on the heap
692// and need to be freed. On input, these strings point into argv.
693// process_tpd() may alter these strings; new values will be on the heap.
694// If process_tpd() preserves the content of such a string (e.g. ets_name),
695// it must nevertheless make a copy on the heap via mcopystr().
696static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg,
697 const char *file_list_path, int *p_argc, char ***p_argv,
af710487 698 int *p_optind, char **p_ets_name, char **p_project_name,
970ed795
EL
699 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
700 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
701 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
702 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
703 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
af710487 704 struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes,
705 struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag,
706 char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag,
707 boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
970ed795
EL
708 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
709 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
af710487 710 string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag,
711 boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir,
712 struct string2_list* run_command_list, map<cstring, int>& seen_tpd_files, struct string2_list* required_configs)
970ed795 713{
af710487 714 tpd_result result = TPD_SUCCESS;
970ed795
EL
715 // read-only non-pointer aliases
716 //char** const& local_argv = *p_argv;
717 int const& local_argc = *p_argc;
718 int const& local_optind = *p_optind;
719 *abs_work_dir_p = NULL;
720
721 assert(local_optind >= 2 // at least '-ttpd_name' must be in the args
722 || local_optind == 0); // if called for a referenced project
723
724 assert(local_argc >= local_optind);
725
726 autostring tpd_dir(get_dir_from_path(p_tpd_name));
727 autostring abs_tpd_dir(get_absolute_dir(tpd_dir, NULL));
af710487 728 if (NULL == (const char*)abs_tpd_dir) {
729 ERROR("absolut TPD directory could not be retreaved from %s", (const char*)tpd_dir);
730 return TPD_FAILED;
731 }
970ed795
EL
732 autostring tpd_filename(get_file_from_path(p_tpd_name));
733 autostring abs_tpd_name(compose_path_name(abs_tpd_dir, tpd_filename));
734
735 if (seen_tpd_files.has_key(abs_tpd_name)) {
736 ++*seen_tpd_files[abs_tpd_name];
737 return TPD_SKIPPED; // nothing to do
738 }
739 else {
740 if (recursive && !prefix_workdir) {
741 // check that this tpd file is not inside a directory of another tpd file
742 for (size_t i = 0; i < seen_tpd_files.size(); ++i) {
743 const cstring& other_tpd_name = seen_tpd_files.get_nth_key(i);
744 autostring other_tpd_dir(get_dir_from_path((const char*)other_tpd_name));
745 if (strcmp((const char*)abs_tpd_dir,(const char*)other_tpd_dir)==0) {
746 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);
747 return TPD_FAILED;
748 }
749 }
750 }
751 // mcopystr makes another copy for the map
752 seen_tpd_files.add(cstring(mcopystr(abs_tpd_name)), new int(1));
753 }
754
755 vector<char> base_files; // values Malloc'd but we pass them to the caller
756
757 XmlDoc doc(xmlParseFile(p_tpd_name));
758 if (doc == NULL) {
759 fprintf(stderr, "Error: unable to parse file \"%s\"\n", p_tpd_name);
760 return TPD_FAILED;
761 }
762
763 if (!Vflag) {
764 // try schema validation if tpd schema file was found
765 bool tpd_is_valid = false;
766 const char* ttcn3_dir = getenv("TTCN3_DIR");
767 if (ttcn3_dir) {
768 size_t ttcn3_dir_len = strlen(ttcn3_dir);
769 bool ends_with_slash = (ttcn3_dir_len>0) && (ttcn3_dir[ttcn3_dir_len - 1]=='/');
770 expstring_t xsd_file_name = mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir, ends_with_slash?"":"/");
771 autostring xsd_file_name_as(xsd_file_name);
772 if (get_path_status(xsd_file_name)==PS_FILE) {
773 if (validate_tpd(doc, p_tpd_name, xsd_file_name)) {
774 tpd_is_valid = true;
775 NOTIFY("TPD file `%s' validated successfully with schema file `%s'", p_tpd_name, xsd_file_name);
776 }
777 } else {
778 ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name);
779 }
780 } else {
781 ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
782 }
783 if (!tpd_is_valid) {
784 return TPD_FAILED;
785 }
786 }
787
788 // Source files.
789 // Key is projectRelativePath, value is relativeURI or rawURI.
790 map<cstring, const char> files; // values Malloc'd
791 map<cstring, const char> folders; // values Malloc'd
792 // NOTE! files and folders must be local variables of process_tpd.
793 // This is because the keys (not the values) are owned by the XmlDoc.
794
795 map<cstring, const char> path_vars;
796
797 XPathContext xpathCtx(xmlXPathNewContext(doc));
798 if (xpathCtx == NULL) {
799 fprintf(stderr,"Error: unable to create new XPath context\n");
800 return TPD_FAILED;
801 }
802 // Collect path variables
803 {
804 XPathObject pathsObj(run_xpath(xpathCtx,
805 "/TITAN_Project_File_Information/PathVariables/PathVariable"));
806 xmlNodeSetPtr nodes = pathsObj->nodesetval;
807
808 const char *name = 0, *value = 0;
809 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
810 // nodes->nodeTab[i]->name === "PathVariable"
811 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
812 if (!strcmp((const char*)attr->name, "name")) {
813 name = (const char*)attr->children->content;
814 }
815 else if (!strcmp((const char*)attr->name, "value")) {
816 value = (const char*)attr->children->content;
817 }
818 else {
819 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
820 }
821 } // next attribute
822
823 if (name && value) path_vars.add(cstring(name), value);
824 else ERROR("A PathVariable must have both name and value");
825 } // next PathVariable
826 }
827
828 // Collect folders
829 {
830 XPathObject foldersObj(run_xpath(xpathCtx,
831 "/TITAN_Project_File_Information/Folders/FolderResource"));
832
833 xmlNodeSetPtr nodes = foldersObj->nodesetval;
834 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
835 // nodes->nodeTab[i]->name === "FolderResource"
836 const char *uri = 0, *path = 0, *raw = 0;
837
838 // projectRelativePath is the path as it appears in Project Explorer (illusion)
839 // relativeURI is the actual location, relative to the project root (reality)
840 // rawURI is present if the relative path can not be calculated
841 //
842 // Theoretically these attributes could be in any order, loop over them
843 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
844 if (!strcmp((const char*)attr->name, "projectRelativePath")) {
845 path = (const char*)attr->children->content;
846 }
847 else if (!strcmp((const char*)attr->name, "relativeURI")) {
848 uri = (const char*)attr->children->content;
849 }
850 else if (!strcmp((const char*)attr->name, "rawURI")) {
851 raw = (const char*)attr->children->content;
852 }
853 else {
854 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
855 }
856 } // next attribute
857
858 if (path == NULL) {
859 ERROR("A FolderResource must have a projectRelativePath");
860 continue;
861 }
862
863 if (uri == NULL && raw == NULL) {
864 ERROR("A FolderResource must have either relativeURI or rawURI");
865 continue;
866 }
867 // relativeURI wins over rawURI
868 folders.add(cstring(path), uri ? mcopystr(uri) : cook(raw, path_vars));
869 // TODO uri: cut "file:", complain on anything else
870 } // next FolderResource
871 }
872
af710487 873 /////////////////////////////////////////////////////////////////////////////
970ed795 874 {
af710487 875 char *projectNameXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()");
876 XPathObject projectNameObj(run_xpath(xpathCtx, projectNameXpath));
877 Free(projectNameXpath);
878 if (projectNameObj->nodesetval && projectNameObj->nodesetval->nodeNr > 0) {
879 *p_project_name = mcopystr((const char*)projectNameObj->nodesetval->nodeTab[0]->content);
880 projGenHelper.addTarget(*p_project_name);
881 projGenHelper.setToplevelProjectName(*p_project_name);
882 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
883 if (projDesc) projDesc->setProjectAbsTpdDir((const char*)abs_tpd_dir);
884 }
885 }
886 /////////////////////////////////////////////////////////////////////////////
887
888 if (!actcfg) {
889 actcfg = get_act_config(required_configs,*p_project_name);
890 }
891 if (actcfg == NULL) {
970ed795
EL
892 // Find out the active config
893 XPathObject activeConfig(run_xpath(xpathCtx,
894 "/TITAN_Project_File_Information/ActiveConfiguration/text()"));
895 if (activeConfig->nodesetval && activeConfig->nodesetval->nodeNr == 1) {
896 // there is one node
897 actcfg = (const char*)activeConfig->nodesetval->nodeTab[0]->content;
898 }
899 }
900
901 if (actcfg == NULL) {
902 ERROR("Can not find the active build configuration.");
903 for (size_t i = 0; i < folders.size(); ++i) {
904 Free(const_cast<char*>(folders.get_nth_elem(i)));
905 }
906 folders.clear();
907 return TPD_FAILED;
908 }
909
910 { // check if the active configuration exists
911 expstring_t xpathActCfg= mprintf(
912 "/TITAN_Project_File_Information/Configurations/"
913 "Configuration[@name='%s']/text()", actcfg);
914 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfg));
915 Free(xpathActCfg);
916
917 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
918 if (nodes == NULL) {
919 ERROR("The active build configuration named '%s' does not exist",
920 actcfg);
921 for (size_t i = 0; i < folders.size(); ++i) {
922 Free(const_cast<char*>(folders.get_nth_elem(i)));
923 }
924 folders.clear();
925 return TPD_FAILED;
926 }
927 }
970ed795
EL
928 // working directory stuff
929 autostring workdir;
930 {
931 const char* workdirFromTpd = "bin"; // default value
932 char *workdirXpath = mprintf(
933 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
934 "/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
935 actcfg);
936 XPathObject workdirObj(run_xpath(xpathCtx, workdirXpath));
937 Free(workdirXpath);
938 if (workdirObj->nodesetval && workdirObj->nodesetval->nodeNr > 0) {
939 workdirFromTpd = (const char*)workdirObj->nodesetval->nodeTab[0]->content;
940 }
941 if (prefix_workdir) { // the working directory is: prjNameStr + "_" + workdirFromTpd
942 const char* prjNameStr = "unnamedproject";
943 XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
944 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
945 prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
946 }
947 workdir = mprintf("%s_%s", prjNameStr, workdirFromTpd);
948 } else {
949 workdir = mcopystr(workdirFromTpd);
950 }
951 }
952 if (!folders.has_key(workdir)) {
953 // Maybe the tpd was saved with the option "No info about work dir"
954 folders.add(workdir, mcopystr(workdir)); // fake it
955 }
956 const char *real_workdir = folders[workdir]; // This is relative to the location of the tpd file
957 excluded_folders.add(real_workdir); // excluded by convention
958
af710487 959 autostring proj_abs_workdir;
960
970ed795
EL
961 autostring abs_workdir;
962 // If -D flag was specified then we ignore the workdir
963 // in the TPD (the current dir is considered the work dir).
964 if (!Dflag) {
965 bool hasWorkDir = false;
966 // if the working directory does not exist create it
967 autostring saved_work_dir(get_working_dir());
968 if (set_working_dir(abs_tpd_dir)) {
969 ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir);
970 } else {
971 switch (get_path_status(real_workdir)) {
972 case PS_FILE:
973 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);
974 break;
975 case PS_DIRECTORY:
976 // already exists
977 hasWorkDir = true;
978 break;
979 default:
980 if (recursive || local_argc != 0) { // we only want to create workdir if necessary
af710487 981 fprintf(stderr, "Working directory `%s' in project `%s' does not exist, trying to create it...\n",
982 real_workdir, (const char*)abs_tpd_dir);
970ed795
EL
983 int rv = mkdir(real_workdir, 0755);
984 if (rv) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno));
985 else printf("Working directory created\n");
986 hasWorkDir = true;
987 }
988 }
989 }
990
991 if (local_argc==0) { // if not top level
992 set_working_dir(saved_work_dir); // restore working directory
993 } else { // if top level
994 set_working_dir(real_workdir); // go into the working dir
995 }
996 if (hasWorkDir) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
997 *abs_work_dir_p = get_absolute_dir(real_workdir, abs_tpd_dir);
998 abs_workdir = (mcopystr(*abs_work_dir_p));
af710487 999 proj_abs_workdir = mcopystr(*abs_work_dir_p);
970ed795
EL
1000 }
1001 }
af710487 1002
1003 if (Dflag) { // the path to subproject working dir is needed to find the linkerlibsearchpath
1004 proj_abs_workdir = compose_path_name(abs_tpd_dir, real_workdir);
1005 }
1006
1007 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1008 if (projDesc) {
1009 projDesc->setProjectAbsWorkingDir((const char*)proj_abs_workdir);
1010 projDesc->setProjectWorkingDir(real_workdir);
1011 projDesc->setTPDFileName(p_tpd_name);
1012 }
1013
970ed795
EL
1014 /////////////////////////////////////////////////////////////////////////////
1015
1016 // Gather the excluded folders in the active config
1017 {
1018 expstring_t xpathActCfgPaths = mprintf(
1019 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1020 "/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
1021 // This was the selection criterium, we need to go up and down for the actual information
1022 "/parent::*/parent::*/FolderPath/text()",
1023 actcfg);
1024 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
1025 Free(xpathActCfgPaths);
1026
1027 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
1028 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1029
1030 excluded_folders.add((const char*)nodes->nodeTab[i]->content);
1031 }
1032 }
1033
1034 // Gather individual excluded files in the active config
1035 {
1036 expstring_t xpathActCfgPaths = mprintf(
1037 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1038 "/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
1039 "/parent::*/parent::*/FilePath/text()",
1040 actcfg);
1041 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
1042 Free(xpathActCfgPaths);
1043
1044 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
1045 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1046 xmlNodePtr curnode = nodes->nodeTab[i];
1047
1048 cstring aa((const char*)curnode->content);
af710487 1049 excluded_files.add(aa, *p_project_name);
970ed795
EL
1050 }
1051 }
1052
1053 // Collect files; filter out excluded ones
1054 {
1055 XPathObject filesObj(run_xpath(xpathCtx,
1056 "TITAN_Project_File_Information/Files/FileResource"));
1057
1058 xmlNodeSetPtr nodes = filesObj->nodesetval;
1059 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1060 // nodes->nodeTab[i]->name === "FileResource"
1061 const char *uri = 0, *path = 0, *raw = 0;
1062
1063 // projectRelativePath is the path as it appears in Project Explorer (illusion)
1064 // relativeURI is the actual location, relative to the project root (reality)
1065 // rawURI is present if the relative path can not be calculated
1066 //
1067 // Theoretically these attributes could be in any order, loop over them
1068 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
1069 if (!strcmp((const char*)attr->name, "projectRelativePath")) {
1070 path = (const char*)attr->children->content;
1071 }
1072 else if (!strcmp((const char*)attr->name, "relativeURI")) {
1073 uri = (const char*)attr->children->content;
1074 }
1075 else if (!strcmp((const char*)attr->name, "rawURI")) {
1076 raw = (const char*)attr->children->content;
1077 }
1078 else {
1079 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
1080 }
1081 } // next attribute
1082
1083 if (path == NULL) {
1084 ERROR("A FileResource must have a projectRelativePath");
1085 continue;
1086 }
1087
1088 if (uri == NULL && raw == NULL) {
1089 ERROR("A FileResource must have either relativeURI or rawURI");
1090 continue;
1091 }
1092
1093 cstring cpath(path);
af710487 1094 if (!is_excluded_file(cpath, *p_project_name) && !is_excluded_folder(path)) {
970ed795
EL
1095 // relativeURI wins over rawURI
1096 char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
970ed795
EL
1097 if (files.has_key(cpath)) {
1098 ERROR("A FileResource %s must be unique!", (const char*)cpath);
af710487 1099 }
1100 else {
1101 const char* file_path = ruri;
1102 expstring_t rel_file_dir = get_dir_from_path(file_path);
1103 expstring_t file_name = get_file_from_path(file_path);
1104 expstring_t abs_dir_path = get_absolute_dir(rel_file_dir, abs_tpd_dir);
1105 expstring_t abs_file_name = compose_path_name(abs_dir_path, file_name);
1106 if (abs_file_name != NULL) {
1107 if (get_path_status(abs_file_name) == PS_FILE) {
1108 FILE *fp = fopen(abs_file_name, "r");
1109 if (fp != NULL) {
1110 char* ttcn3_module_name;
1111 if (is_ttcn3_module(abs_file_name, fp, &ttcn3_module_name)) {
1112 projGenHelper.addTtcn3ModuleToProject(*p_project_name, ttcn3_module_name);
1113 }
1114 Free(ttcn3_module_name);
1115 char* asn1_module_name;
1116 if (is_asn1_module(abs_file_name, fp, &asn1_module_name)) {
1117 projGenHelper.addAsn1ModuleToProject(*p_project_name, asn1_module_name);
1118 }
1119 Free(asn1_module_name);
1120 if (projGenHelper.isCPPSourceFile(file_name)) {
1121 projGenHelper.addUserSourceToProject(*p_project_name, file_name);
1122 }
1123 if (projGenHelper.isCPPHeaderFile(file_name)) {
1124 projGenHelper.addUserHeaderToProject(*p_project_name, file_name);
1125 }
1126 if (projGenHelper.isTtcnPPFile(file_name)) {
1127 projGenHelper.addTtcnPPToProject(*p_project_name, file_name);
1128 }
1129 }
1130 fclose(fp);
1131 }
1132 }
970ed795
EL
1133 files.add(cpath, ruri); // relativeURI to the TPD location
1134 { // set the *preprocess value if .ttcnpp file was found
1135 const size_t ttcnpp_extension_len = 7; // ".ttcnpp"
1136 const size_t ruri_len = strlen(ruri);
1137 if ( ruri_len>ttcnpp_extension_len && strcmp(ruri+(ruri_len-ttcnpp_extension_len),".ttcnpp")==0 ) {
1138 *preprocess = TRUE;
1139 }
1140 }
af710487 1141 Free(rel_file_dir);
1142 Free(file_name);
1143 Free(abs_dir_path);
1144 Free(abs_file_name);
970ed795
EL
1145 }
1146 }
1147 } // next FileResource
1148 }
1149
1150 // Check options
1151 xsdbool2boolean(xpathCtx, actcfg, "useAbsolutePath", p_aflag);
1152 xsdbool2boolean(xpathCtx, actcfg, "GNUMake", p_gflag);
af710487 1153 if (*p_Zflag) *p_lflag = FALSE;
970ed795
EL
1154 xsdbool2boolean(xpathCtx, actcfg, "dynamicLinking", p_lflag);
1155 xsdbool2boolean(xpathCtx, actcfg, "functiontestRuntime", p_Rflag);
1156 xsdbool2boolean(xpathCtx, actcfg, "singleMode", p_sflag);
1157 xsdbool2boolean(xpathCtx, actcfg, "codeSplitting", p_csflag);
1158 xsdbool2boolean(xpathCtx, actcfg, "quietly", p_quflag);
1159 xsdbool2boolean(xpathCtx, actcfg, "disableSubtypeChecking", p_dsflag);
1160 xsdbool2boolean(xpathCtx, actcfg, "disableBER", p_dbflag);
1161 xsdbool2boolean(xpathCtx, actcfg, "disableRAW", p_drflag);
1162 xsdbool2boolean(xpathCtx, actcfg, "disableTEXT", p_dtflag);
1163 xsdbool2boolean(xpathCtx, actcfg, "disableXER", p_dxflag);
1164 xsdbool2boolean(xpathCtx, actcfg, "disableJSON", p_djflag);
1165 xsdbool2boolean(xpathCtx, actcfg, "forceXERinASN.1", p_fxflag);
1166 xsdbool2boolean(xpathCtx, actcfg, "defaultasOmit", p_doflag);
1167 xsdbool2boolean(xpathCtx, actcfg, "gccMessageFormat", p_gfflag);
1168 xsdbool2boolean(xpathCtx, actcfg, "lineNumbersOnlyInMessages", p_lnflag);
1169 xsdbool2boolean(xpathCtx, actcfg, "includeSourceInfo", p_isflag);
1170 xsdbool2boolean(xpathCtx, actcfg, "addSourceLineInfo", p_asflag);
1171 xsdbool2boolean(xpathCtx, actcfg, "suppressWarnings", p_swflag);
1172 xsdbool2boolean(xpathCtx, actcfg, "outParamBoundness", p_Yflag);
1173
af710487 1174 projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1175 if (projDesc) projDesc->setLinkingStrategy(*p_lflag);
1176
970ed795
EL
1177 // Extract the "incremental dependencies" option
1178 {
1179 boolean incremental_deps = TRUE;
1180 xsdbool2boolean(xpathCtx, actcfg, "incrementalDependencyRefresh", &incremental_deps);
1181
1182 // For makefilegen, "Use GNU make" implies incremental deps by default,
1183 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
1184 // For Eclipse, incremental deps must be explicitly specified,
1185 // even if GNU make is being used.
1186
1187 if (incremental_deps) {
1188 if( !(*p_gflag) ) {
1189 WARNING("Incremental dependency ordered but it requires gnu make");
1190 }
1191 }
1192 else {
1193 if (*p_gflag) {
1194 // GNU make but no incremental deps
1195 *p_mflag = true;
1196 }
1197 }
1198 }
1199
1200 // Extract the default target option
1201 // if it is not defined as a command line argument
1202 if (!(*p_Lflag)) {
af710487 1203 expstring_t defTargetXpath = mprintf(
970ed795
EL
1204 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1205 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
1206 actcfg);
1207 XPathObject defTargetObj(run_xpath(xpathCtx, defTargetXpath));
1208 Free(defTargetXpath);
1209 if (defTargetObj->nodesetval && defTargetObj->nodesetval->nodeNr > 0) {
1210 const char* content = (const char*)defTargetObj->nodesetval->nodeTab[0]->content;
1211 if (!strcmp(content, "library")) {
1212 *p_Lflag = true;
1213 } else if (!strcmp(content, "executable")) {
1214 *p_Lflag = false;
1215 } else {
1216 ERROR("Unknown default target: '%s'."
1217 " The available targets are: 'executable', 'library'", content);
1218 }
1219 }
af710487 1220 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1221 if (projDesc) projDesc->setLibrary(*p_Lflag);
970ed795
EL
1222 }
1223
1224 // Executable name (don't care unless top-level invocation)
1225 if (local_argc != 0)
1226 {
1227 char *exeXpath = mprintf(
1228 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1229 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
1230 actcfg);
1231 XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
1232 Free(exeXpath);
1233 if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
1234 const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
1235 autostring target_exe_dir(get_dir_from_path(target_executable));
1236 autostring target_exe_file(get_file_from_path(target_executable));
1237 if (target_exe_dir!=NULL) { // if it's not only a file name
1238 if (get_path_status(target_exe_dir)==PS_NONEXISTENT) {
1239 if (strcmp(real_workdir,target_exe_dir)!=0) {
1240 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);
1241 }
1242 target_executable = target_exe_file;
1243 }
1244 }
1245 if (!*p_ets_name) { // Command line will win
1246 *p_ets_name = mcopystr(target_executable);
1247 }
1248 }
1249 }
1250
1251 // create an xml element for the currently processed project
1252 if (prj_graph_fp) {
1253 const char* prjNameStr = "???";
1254 XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
1255 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
1256 prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
1257 }
1258 autostring tpd_rel_dir(get_relative_dir(tpd_dir, NULL));
1259 autostring tpd_rel_path(compose_path_name(tpd_rel_dir, (const char*)tpd_filename));
1260 fprintf(prj_graph_fp, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr, (const char*)tpd_rel_path);
1261 XPathObject subprojects(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
1262 xmlNodeSetPtr nodes = subprojects->nodesetval;
1263 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1264 const char* refd_name = "???";
1265 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1266 refd_name = (const char*)nodes->nodeTab[i]->children->content;
1267 }
1268 fprintf(prj_graph_fp, "<reference name=\"%s\"/>\n", refd_name);
1269 }
1270 fprintf(prj_graph_fp, "</project>\n");
1271 }
1272
1273 // Tpd part of the MakefileSettings
1274 {
1275 //TTCN3preprocessorIncludes
1276 char *preincludeXpath = mprintf(
1277 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1278 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
1279 actcfg);
1280 XPathObject preincludeObj(run_xpath(xpathCtx, preincludeXpath));
1281 Free(preincludeXpath);
1282
1283 xmlNodeSetPtr nodes = preincludeObj->nodesetval;
1284
1285 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1286 char* content = (char*)preincludeObj->nodesetval->nodeTab[i]->content;
1287
1288 // add includes to the end of list
1289 if (ttcn3_prep_includes) {
1290 // go to last element
1291 struct string_list* last_elem = ttcn3_prep_includes;
1292 while (last_elem->next) last_elem = last_elem->next;
1293 // add string to last element if empty or create new last element and add it to that
1294 if (last_elem->str) {
1295 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1296 last_elem = last_elem->next;
1297 last_elem->next = NULL;
1298 }
1299 replacechar(&content);
1300 last_elem->str = content;
1301 }
1302 }
1303 }
1304 {
1305 //TTCN3preprocessorDefines
1306 char *ttcn3predefinesXpath = mprintf(
1307 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1308 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
1309 actcfg);
1310 XPathObject ttcn3predefinesObj(run_xpath(xpathCtx, ttcn3predefinesXpath));
1311 Free(ttcn3predefinesXpath);
1312
1313 xmlNodeSetPtr nodes = ttcn3predefinesObj->nodesetval;
1314
1315 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1316 const char* content = (const char*)ttcn3predefinesObj->nodesetval->nodeTab[i]->content;
1317
1318 // add includes to the end of list
1319 if (ttcn3_prep_defines) {
1320 // go to last element
1321 struct string_list* last_elem = ttcn3_prep_defines;
1322 while (last_elem->next) last_elem = last_elem->next;
1323 // add string to last element if empty or create new last element and add it to that
1324 if (last_elem->str) {
1325 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1326 last_elem = last_elem->next;
1327 last_elem->next = NULL;
1328 }
1329 last_elem->str = mcopystr(content);
1330 }
1331 }
1332 }
af710487 1333 {
1334 //TTCN3preprocessorUnDefines
1335 char *ttcn3preUndefinesXpath = mprintf(
1336 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1337 "/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()",
1338 actcfg);
1339 XPathObject ttcn3preUndefinesObj(run_xpath(xpathCtx, ttcn3preUndefinesXpath));
1340 Free(ttcn3preUndefinesXpath);
1341
1342 xmlNodeSetPtr nodes = ttcn3preUndefinesObj->nodesetval;
1343
1344 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1345 const char* content = (const char*)ttcn3preUndefinesObj->nodesetval->nodeTab[i]->content;
1346
1347 // add includes to the end of list
1348 if (ttcn3_prep_undefines) {
1349 // go to last element
1350 struct string_list* last_elem = ttcn3_prep_undefines;
1351 while (last_elem->next) last_elem = last_elem->next;
1352 // add string to last element if empty or create new last element and add it to that
1353 if (last_elem->str) {
1354 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1355 last_elem = last_elem->next;
1356 last_elem->next = NULL;
1357 }
1358 last_elem->str = mcopystr(content);
1359 }
1360 }
1361 }
1362
970ed795
EL
1363 {
1364 //preprocessorIncludes
1365 char *preincludesXpath = mprintf(
1366 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1367 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
1368 actcfg);
1369 XPathObject preincludesObj(run_xpath(xpathCtx, preincludesXpath));
1370 Free(preincludesXpath);
1371
1372 xmlNodeSetPtr nodes = preincludesObj->nodesetval;
1373
1374 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1375 char* content = (char*)preincludesObj->nodesetval->nodeTab[i]->content;
1376
1377 // add includes to the end of list
1378 if (prep_includes) {
1379 // go to last element
1380 struct string_list* last_elem = prep_includes;
1381 while (last_elem->next) last_elem = last_elem->next;
1382 // add string to last element if empty or create new last element and add it to that
1383 if (last_elem->str) {
1384 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1385 last_elem = last_elem->next;
1386 last_elem->next = NULL;
1387 }
1388 replacechar(&content);
1389 last_elem->str = content;
1390 }
1391 }
1392 }
1393 {
1394 //preprocessorDefines
1395 char *predefinesXpath = mprintf(
1396 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1397 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
1398 actcfg);
1399 XPathObject predefinesObj(run_xpath(xpathCtx, predefinesXpath));
1400 Free(predefinesXpath);
1401
1402 xmlNodeSetPtr nodes = predefinesObj->nodesetval;
1403
1404 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1405 const char* content = (const char*)predefinesObj->nodesetval->nodeTab[i]->content;
1406
1407 // add includes to the end of list
1408 if (prep_defines) {
1409 // go to last element
1410 struct string_list* last_elem = prep_defines;
1411 while (last_elem->next) last_elem = last_elem->next;
1412 // add string to last element if empty or create new last element and add it to that
1413 if (last_elem->str) {
1414 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1415 last_elem = last_elem->next;
1416 last_elem->next = NULL;
1417 }
1418 last_elem->str = mcopystr(content);
1419 }
1420 }
1421 }
af710487 1422 {
1423 //preprocessorUnDefines
1424 char *preUndefinesXpath = mprintf(
1425 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1426 "/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()",
1427 actcfg);
1428 XPathObject preUndefinesObj(run_xpath(xpathCtx, preUndefinesXpath));
1429 Free(preUndefinesXpath);
1430
1431 xmlNodeSetPtr nodes = preUndefinesObj->nodesetval;
1432
1433 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1434 const char* content = (const char*)preUndefinesObj->nodesetval->nodeTab[i]->content;
1435
1436 // add includes to the end of list
1437 if (prep_undefines) {
1438 // go to last element
1439 struct string_list* last_elem = prep_undefines;
1440 while (last_elem->next) last_elem = last_elem->next;
1441 // add string to last element if empty or create new last element and add it to that
1442 if (last_elem->str) {
1443 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1444 last_elem = last_elem->next;
1445 last_elem->next = NULL;
1446 }
1447 last_elem->str = mcopystr(content);
1448 }
1449 }
1450 }
970ed795
EL
1451 {
1452 char *cxxCompilerXpath = mprintf(
1453 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1454 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1455 actcfg);
1456 XPathObject cxxCompilerObj(run_xpath(xpathCtx, cxxCompilerXpath));
1457 Free(cxxCompilerXpath);
1458 xmlNodeSetPtr nodes = cxxCompilerObj->nodesetval;
1459 if (nodes) {
1460 *cxxcompiler = mcopystr((const char*)cxxCompilerObj->nodesetval->nodeTab[0]->content);
1461 }
1462 }
1463 {
1464 char *optLevelXpath = mprintf(
1465 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1466 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1467 actcfg);
1468 XPathObject optLevelObj(run_xpath(xpathCtx, optLevelXpath));
1469 Free(optLevelXpath);
1470 xmlNodeSetPtr nodes = optLevelObj->nodesetval;
1471 if (nodes) {
1472 *optlevel = mcopystr((const char*)optLevelObj->nodesetval->nodeTab[0]->content);
1473 }
1474 }
1475 {
1476 char *optFlagsXpath = mprintf(
1477 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1478 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1479 actcfg);
1480 XPathObject optFlagsObj(run_xpath(xpathCtx, optFlagsXpath));
1481 Free(optFlagsXpath);
1482 xmlNodeSetPtr nodes = optFlagsObj->nodesetval;
1483 if (nodes) {
1484 *optflags = mcopystr((const char*)optFlagsObj->nodesetval->nodeTab[0]->content);
1485 }
1486 }
1487 {
1488 //SolarisSpecificLibraries
1489 char *solspeclibXpath = mprintf(
1490 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1491 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1492 actcfg);
1493 XPathObject solspeclibObj(run_xpath(xpathCtx, solspeclibXpath));
1494 Free(solspeclibXpath);
1495
1496 xmlNodeSetPtr nodes = solspeclibObj->nodesetval;
1497
1498 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1499 char* content = (char*)solspeclibObj->nodesetval->nodeTab[i]->content;
1500
1501 // add includes to the end of list
1502 if (solspeclibs) {
1503 // go to last element
1504 struct string_list* last_elem =solspeclibs;
1505 while (last_elem->next) last_elem = last_elem->next;
1506 // add string to last element if empty or create new last element and add it to that
1507 if (last_elem->str) {
1508 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1509 last_elem = last_elem->next;
1510 last_elem->next = NULL;
1511 }
1512 replacechar(&content);
1513 last_elem->str = content;
1514 }
1515 }
1516 }
1517 {
1518 //Solaris8SpecificLibraries
1519 char *sol8speclibXpath = mprintf(
1520 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1521 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1522 actcfg);
1523 XPathObject sol8speclibObj(run_xpath(xpathCtx, sol8speclibXpath));
1524 Free(sol8speclibXpath);
1525
1526 xmlNodeSetPtr nodes = sol8speclibObj->nodesetval;
1527
1528 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1529 char* content = (char*)sol8speclibObj->nodesetval->nodeTab[i]->content;
1530
1531 // add includes to the end of list
1532 if (sol8speclibs) {
1533 // go to last element
1534 struct string_list* last_elem = sol8speclibs;
1535 while (last_elem->next) last_elem = last_elem->next;
1536 // add string to last element if empty or create new last element and add it to that
1537 if (last_elem->str) {
1538 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1539 last_elem = last_elem->next;
1540 last_elem->next = NULL;
1541 }
1542 replacechar(&content);
1543 last_elem->str = content;
1544 }
1545 }
1546 }
1547 {
1548 //LinuxSpecificLibraries
1549 char *linuxspeclibXpath = mprintf(
1550 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1551 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1552 actcfg);
1553 XPathObject linuxspeclibObj(run_xpath(xpathCtx, linuxspeclibXpath));
1554 Free(linuxspeclibXpath);
1555
1556 xmlNodeSetPtr nodes = linuxspeclibObj->nodesetval;
1557
1558 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1559 char* content = (char*)linuxspeclibObj->nodesetval->nodeTab[i]->content;
1560
1561 // add includes to the end of list
1562 if (linuxspeclibs) {
1563 // go to last element
1564 struct string_list* last_elem = linuxspeclibs;
1565 while (last_elem->next) last_elem = last_elem->next;
1566 // add string to last element if empty or create new last element and add it to that
1567 if (last_elem->str) {
1568 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1569 last_elem = last_elem->next;
1570 last_elem->next = NULL;
1571 }
1572 replacechar(&content);
1573 last_elem->str = content;
1574 }
1575 }
1576 }
1577 {
1578 //FreeBSDSpecificLibraries
1579 char *freebsdspeclibXpath = mprintf(
1580 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1581 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1582 actcfg);
1583 XPathObject freebsdspeclibObj(run_xpath(xpathCtx, freebsdspeclibXpath));
1584 Free(freebsdspeclibXpath);
1585
1586 xmlNodeSetPtr nodes = freebsdspeclibObj->nodesetval;
1587
1588 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1589 char* content = (char*)freebsdspeclibObj->nodesetval->nodeTab[i]->content;
1590
1591 // add includes to the end of list
1592 if (freebsdspeclibs) {
1593 // go to last element
1594 struct string_list* last_elem = freebsdspeclibs;
1595 while (last_elem->next) last_elem = last_elem->next;
1596 // add string to last element if empty or create new last element and add it to that
1597 if (last_elem->str) {
1598 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1599 last_elem = last_elem->next;
1600 last_elem->next = NULL;
1601 }
1602 replacechar(&content);
1603 last_elem->str = content;
1604 }
1605 }
1606 }
1607 {
1608 //Win32SpecificLibraries
1609 char *win32speclibXpath = mprintf(
1610 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1611 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1612 actcfg);
1613 XPathObject win32speclibObj(run_xpath(xpathCtx, win32speclibXpath));
1614 Free(win32speclibXpath);
1615
1616 xmlNodeSetPtr nodes = win32speclibObj->nodesetval;
1617
1618 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1619 char* content = (char*)win32speclibObj->nodesetval->nodeTab[i]->content;
1620
1621 // add includes to the end of list
1622 if (win32speclibs) {
1623 // go to last element
1624 struct string_list* last_elem = win32speclibs;
1625 while (last_elem->next) last_elem = last_elem->next;
1626 // add string to last element if empty or create new last element and add it to that
1627 if (last_elem->str) {
1628 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1629 last_elem = last_elem->next;
1630 last_elem->next = NULL;
1631 }
1632 replacechar(&content);
1633 last_elem->str = content;
1634 }
1635
1636 }
1637 }
1638 {
1639 //TTCN3preprocessor
1640 char *ttcn3preproc = mprintf(
1641 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1642 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1643 actcfg);
1644 XPathObject ttcn3preprocObj(run_xpath(xpathCtx, ttcn3preproc));
1645 Free(ttcn3preproc);
1646 xmlNodeSetPtr nodes = ttcn3preprocObj->nodesetval;
1647 if (nodes) {
1648 *ttcn3prep = mcopystr((const char*)ttcn3preprocObj->nodesetval->nodeTab[0]->content);
1649 }
1650 }
1651 {
1652 // additionalObjects
1653 char *additionalObjectsXpath = mprintf(
1654 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1655 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1656 actcfg);
1657 XPathObject additionalObjectsObj(run_xpath(xpathCtx, additionalObjectsXpath));
1658 Free(additionalObjectsXpath);
1659
1660 xmlNodeSetPtr nodes = additionalObjectsObj->nodesetval;
1661
1662 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1663 char* content = (char*)additionalObjectsObj->nodesetval->nodeTab[i]->content;
1664
1665 // add to the end of list
1666 if (additionalObjects) {
1667 // go to last element
1668 struct string_list* last_elem = additionalObjects;
1669 while (last_elem->next) last_elem = last_elem->next;
1670 // add string to last element if empty or create new last element and add it to that
1671 if (last_elem->str) {
1672 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1673 last_elem = last_elem->next;
1674 last_elem->next = NULL;
1675 }
1676 replacechar(&content);
1677 last_elem->str = content;
1678 }
1679 }
1680 }
1681 {
af710487 1682 //The project name needed the hierarchical projects
1683 char* prjNameStr = 0;
1684 char *prjNameStrXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()");
1685 XPathObject prjName(run_xpath(xpathCtx, prjNameStrXpath));
1686 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
1687 prjNameStr = (char*)prjName->nodesetval->nodeTab[0]->content;
1688 }
1689 Free(prjNameStrXpath);
1690 append_to_library_list (prjNameStr, xpathCtx, actcfg);
1691
970ed795
EL
1692 //linkerLibraries
1693 char *linkerlibsXpath = mprintf(
1694 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1695 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1696 actcfg);
1697 XPathObject linkerlibsObj(run_xpath(xpathCtx, linkerlibsXpath));
1698 Free(linkerlibsXpath);
1699
1700 xmlNodeSetPtr nodes = linkerlibsObj->nodesetval;
1701
1702 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1703 char* content = (char*)linkerlibsObj->nodesetval->nodeTab[i]->content;
1704
1705 // add includes to the end of list
1706 if (linkerlibs) {
1707 // go to last element
1708 struct string_list* last_elem = linkerlibs;
1709 while (last_elem->next) last_elem = last_elem->next;
1710 // add string to last element if empty or create new last element and add it to that
1711 if (last_elem->str) {
1712 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1713 last_elem = last_elem->next;
1714 last_elem->next = NULL;
1715 }
1716 replacechar(&content);
1717 last_elem->str = content;
af710487 1718
1719 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1720 if (projDesc) projDesc->addToLinkerLibs(last_elem->str);
970ed795
EL
1721 }
1722 }
1723 }
1724 {
1725 //linkerLibrarySearchPath
1726 char *linkerlibsearchXpath = mprintf(
1727 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1728 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1729 actcfg);
1730 XPathObject linkerlibsearchObj(run_xpath(xpathCtx, linkerlibsearchXpath));
1731 Free(linkerlibsearchXpath);
1732
1733 xmlNodeSetPtr nodes = linkerlibsearchObj->nodesetval;
1734
1735 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1736 char* content = (char*)linkerlibsearchObj->nodesetval->nodeTab[i]->content;
1737
1738 // add includes to the end of list
1739 if (linkerlibsearchp) {
1740 // go to last element
1741 struct string_list* last_elem = linkerlibsearchp;
1742 while (last_elem->next) last_elem = last_elem->next;
1743 // add string to last element if empty or create new last element and add it to that
1744 if (last_elem->str) {
1745 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1746 last_elem = last_elem->next;
1747 last_elem->next = NULL;
1748 }
1749 replacechar(&content);
1750 last_elem->str = content;
af710487 1751
1752 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1753 if (projDesc) projDesc->addToLibSearchPaths(last_elem->str);
970ed795
EL
1754 }
1755 }
1756 }
1757
1758 if (generatorCommandOutput && local_argc != 0) { // only in case of top-level invocation
1759 char* generatorCommandXpath = mprintf(
1760 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1761 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1762 actcfg);
1763 XPathObject generatorCommandObj(run_xpath(xpathCtx, generatorCommandXpath));
1764 Free(generatorCommandXpath);
1765 autostring generatorCommand;
1766 if (generatorCommandObj->nodesetval && generatorCommandObj->nodesetval->nodeNr > 0) {
1767 generatorCommand = mcopystr((const char*)generatorCommandObj->nodesetval->nodeTab[0]->content);
1768 // run the command and capture the output
1769 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand, (const char*)abs_tpd_name);
1770 FILE* gc_fp = popen(generatorCommand, "r");
1771 if (!gc_fp) {
1772 ERROR("Could not execute command `%s'", (const char*)generatorCommand);
1773 } else {
1774 char buff[1024];
1775 while (fgets(buff, sizeof(buff), gc_fp)!=NULL) {
1776 *generatorCommandOutput = mputstr(*generatorCommandOutput, buff);
1777 }
1778 pclose(gc_fp);
1779 }
1780 }
1781 }
1782
1783 if (target_placement_list && local_argc != 0) { // only in case of top-level invocation
1784 char* targetPlacementXpath = mprintf(
1785 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1786 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1787 actcfg);
1788 XPathObject targetPlacementObj(run_xpath(xpathCtx, targetPlacementXpath));
1789 Free(targetPlacementXpath);
1790 xmlNodeSetPtr nodes = targetPlacementObj->nodesetval;
1791 const char* targetName = NULL;
1792 const char* targetPlacement = NULL;
1793 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1794 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1795 targetName = (const char*)nodes->nodeTab[i]->children->content;
1796 }
1797 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"placement")) {
1798 targetPlacement = (const char*)nodes->nodeTab[i]->children->content;
1799 }
1800 if (targetName && targetPlacement) { // collected both
1801 if (target_placement_list) {
1802 // go to last element
1803 struct string2_list* last_elem = target_placement_list;
1804 while (last_elem->next) last_elem = last_elem->next;
1805 // add strings to last element if empty or create new last element and add it to that
1806 if (last_elem->str1) {
1807 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1808 last_elem = last_elem->next;
1809 last_elem->next = NULL;
1810 }
1811 last_elem->str1 = mcopystr(targetName);
1812 last_elem->str2 = mcopystr(targetPlacement);
1813 }
1814 targetName = targetPlacement = NULL; // forget both
1815 }
1816 }
1817 }
1818
af710487 1819// collect the required configurations
1820 {
1821 if (required_configs) {
1822 char* cfgReqsXpath(mprintf(
1823 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1824 "/ProjectProperties/ConfigurationRequirements/configurationRequirement",
1825 actcfg));
1826 XPathObject reqcfgObjects(run_xpath(xpathCtx, cfgReqsXpath));
1827 Free (cfgReqsXpath);
1828 xmlNodeSetPtr configs = reqcfgObjects->nodesetval;
1829 if (configs) for (int i = 0; i < configs->nodeNr; ++i) {
1830 xmlNodePtr curNodePtr = configs->nodeTab[i]->children;
1831 const char* projectName = NULL;
1832 const char* reqConfig = NULL;
1833 while(curNodePtr) {
1834 if (!strcmp((const char*)curNodePtr->name, "projectName")) {
1835 projectName = (const char*)curNodePtr->children->content;
1836 }
1837 if (!strcmp((const char*)curNodePtr->name, "rerquiredConfiguration") || // backward compatibility
1838 !strcmp((const char*)curNodePtr->name, "requiredConfiguration")) {
1839 reqConfig = (const char*)curNodePtr->children->content;
1840 }
1841 curNodePtr = curNodePtr->next;
1842 }
1843 struct string2_list* last_elem = required_configs;
1844 bool duplicate = false;
1845 while (last_elem->next) {
1846 if (!strcmp(last_elem->str1, projectName) && !strcmp(last_elem->str2, reqConfig)) {
1847 duplicate = true;
1848 }
1849 else if (!strcmp(last_elem->str1, projectName) && strcmp(last_elem->str2, reqConfig)) {
1850 ERROR("Required configuration is inconsistent : Project '%s' cannot have 2 "
1851 "different configuration '%s' '%s'",
1852 last_elem->str1, last_elem->str2, reqConfig);
1853 result = TPD_FAILED;
1854 }
1855 last_elem = last_elem->next;
1856 }
1857 // add string to last element if empty or create new last element and add it to that
1858 if (last_elem->str1 && !duplicate) {
1859 if (strcmp(last_elem->str1, projectName) || strcmp(last_elem->str2, reqConfig)) {
1860 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1861 last_elem = last_elem->next;
1862 last_elem->next = NULL;
1863 }
1864 else {
1865 duplicate = true;
1866 }
1867 }
1868 if (!duplicate) {
1869 last_elem->str1 = mcopystr(projectName);
1870 last_elem->str2 = mcopystr(reqConfig);
1871 }
1872 }
1873 }
1874 }
1875
970ed795
EL
1876 // Referenced projects
1877 {
1878 XPathObject subprojects(run_xpath(xpathCtx,
1879 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::*"));
1880 xmlNodeSetPtr nodes = subprojects->nodesetval;
1881 const char *name = NULL, *projectLocationURI = NULL;
1882 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1883 // FIXME: this assumes every ReferencedProject has name and URI.
1884 // This is not necessarily so if the referenced project was closed
1885 // when the project was exported to TPD.
1886 // Luckily, the name from the closed project will be overwritten
1887 // by the name from the next ReferencedProject. However, if some pervert
1888 // changes the next ReferencedProject to have the projectLocationURI
1889 // as the first attribute, it will be joined to the name
1890 // of the previous, closed, ReferencedProject.
1891 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1892 name = (const char*)nodes->nodeTab[i]->children->content;
1893 }
1894 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"projectLocationURI")) {
1895 projectLocationURI = (const char*)nodes->nodeTab[i]->children->content;
1896 }
1897
1898 if (name && projectLocationURI) { // collected both
1899 // see if there is a specified configuration for the project
970ed795 1900
af710487 1901 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1902 if (projDesc) projDesc->addToReferencedProjects(name);
1903
1904 const char *my_actcfg = NULL;
970ed795
EL
1905 int my_argc = 0;
1906 char *my_args[] = { NULL };
1907 char **my_argv = my_args + 0;
1908 int my_optind = 0;
1909 boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down
af710487 1910 my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, my_Zflag = *p_Zflag, my_Hflag = *p_Hflag,
970ed795
EL
1911 my_sflag = 0, my_Lflag = 0, my_lflag = 0, my_mflag = 0, my_csflag = 0,
1912 my_quflag = 0, my_dsflag = 0, my_dbflag = 0, my_drflag = 0,
1913 my_dtflag = 0, my_dxflag = 0, my_djflag = 0, my_fxflag = 0, my_doflag = 0,
1914 my_gfflag = 0, my_lnflag = 0, my_isflag = 0, my_asflag = 0,
1915 my_swflag = 0, my_Yflag = 0;
1916
1917 char *my_ets = NULL;
af710487 1918 char *my_proj_name = NULL;
970ed795
EL
1919 autostring abs_projectLocationURI(
1920 compose_path_name(abs_tpd_dir, projectLocationURI));
1921
1922 char* sub_proj_abs_work_dir = NULL;
af710487 1923
970ed795 1924 tpd_result success = process_tpd_internal((const char*)abs_projectLocationURI,
af710487 1925 my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets, &my_proj_name,
970ed795
EL
1926 &my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag,
1927 &my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir,
af710487 1928 sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines,
1929 prep_includes, prep_defines, prep_undefines, &my_csflag,
970ed795
EL
1930 &my_quflag, &my_dsflag, cxxcompiler, optlevel, optflags, &my_dbflag, &my_drflag,
1931 &my_dtflag, &my_dxflag, &my_djflag, &my_fxflag, &my_doflag,
1932 &my_gfflag, &my_lnflag, &my_isflag, &my_asflag, &my_swflag, &my_Yflag, solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs,
af710487 1933 ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, &my_Zflag,
1934 &my_Hflag, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files, required_configs);
1935
970ed795
EL
1936 autostring sub_proj_abs_work_dir_as(sub_proj_abs_work_dir); // ?!
1937
1938 if (success == TPD_SUCCESS) {
af710487 1939 my_actcfg = get_act_config(required_configs, my_proj_name);
970ed795
EL
1940 if (recursive) { // call ttcn3_makefilegen on referenced project's tpd file
1941 // -r is not needed any more because top level process traverses all projects recursively
1942 expstring_t command = mprintf("%s -cVD", program_name);
1943 if (force_overwrite) command = mputc(command, 'f');
1944 if (prefix_workdir) command = mputc(command, 'W');
1945 if (*p_gflag) command = mputc(command, 'g');
1946 if (*p_sflag) command = mputc(command, 's');
1947 if (*p_aflag) command = mputc(command, 'a');
1948 if (*p_Rflag) command = mputc(command, 'R');
1949 if (*p_lflag) command = mputc(command, 'l');
1950 if (*p_mflag) command = mputc(command, 'm');
af710487 1951 if (*p_Zflag) command = mputc(command, 'Z');
1952 if (*p_Hflag) command = mputc(command, 'H');
970ed795
EL
1953 command = mputstr(command, " -t ");
1954 command = mputstr(command, (const char*)abs_projectLocationURI);
1955 if (my_actcfg) {
1956 command = mputstr(command, " -b ");
1957 command = mputstr(command, my_actcfg);
1958 }
1959
1960 autostring sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI));
1961 const char * sub_proj_effective_work_dir = sub_proj_abs_work_dir ? sub_proj_abs_work_dir : (const char*)sub_tpd_dir;
1962 if (!gen_only_top_level) {
1963 if (run_command_list) {
1964 // go to last element
1965 struct string2_list* last_elem = run_command_list;
1966 while (last_elem->next) last_elem = last_elem->next;
1967 // add strings to last element if empty or create new last element and add it to that
1968 if (last_elem->str1 || last_elem->str2) {
1969 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1970 last_elem = last_elem->next;
1971 last_elem->next = NULL;
1972 }
1973 last_elem->str1 = mcopystr(sub_proj_effective_work_dir);
1974 last_elem->str2 = command;
1975 } else {
1976 ERROR("Internal error: cannot add command to list");
1977 }
1978 }
1979 // add working dir to the end of list
1980 if (sub_project_dirs) {
1981 // go to last element
1982 struct string_list* last_elem = sub_project_dirs;
1983 while (last_elem->next) last_elem = last_elem->next;
1984 // add string to last element if empty or create new last element and add it to that
1985 if (last_elem->str) {
1986 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1987 last_elem = last_elem->next;
1988 last_elem->next = NULL;
1989 }
1990 autostring cwd_as(get_working_dir());
1991 last_elem->str = (*p_aflag) ? mcopystr(sub_proj_effective_work_dir) : get_relative_dir(sub_proj_effective_work_dir, (const char*)cwd_as);
1992 }
1993 }
1994
1995 for (int z = 0; z < my_argc; ++z) {
1996 if (*p_cflag) {
1997 // central storage, keep in separate container
1998 base_files.add(my_argv[z]); // string was allocated with new
1999 }
2000 else {
2001 const cstring tmp(my_argv[z]);
2002 if (!files.has_key(tmp)){
2003 files.add(tmp, my_argv[z]);
2004 } else {
2005 Free(my_argv[z]);
2006 }
2007 }
2008 }
2009
2010 Free(my_argv); // free the array; we keep the pointers
2011 Free(my_ets);
af710487 2012 Free(my_proj_name);
970ed795
EL
2013 }
2014 else if (success == TPD_FAILED) {
2015 ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
2016 }
2017 // else TPD_SKIPPED, keep quiet
2018
2019 name = projectLocationURI = NULL; // forget both
2020 }
2021 } // next referenced project
2022 }
2023
2024 if (output_file) {
2025 if (get_path_status(output_file) == PS_DIRECTORY) {
2026 // points to existing dir; use as-is
2027 }
2028 else { // we assume it points to a file: not our problem
2029 output_file = NULL;
2030 }
2031 }
2032
2033 // (argc - optind) is the number of non-option arguments (assumed to be files)
2034 // given on the command line.
2035 int new_argc = local_argc - local_optind + files.size() + base_files.size();
2036 char ** new_argv = (char**)Malloc(sizeof(char*) * new_argc);
2037
2038 int n = 0;
2039
2040 // First, copy the filenames gathered from the TPD
2041 //
2042 // We symlink the files into the working directory
2043 // and pass only the filename to the makefile generator
2044 for (int nf = files.size(); n < nf; ++n) {
2045 const char *fn = files.get_nth_elem(n); // relativeURI to the TPD location
2046 autostring dir_n (get_dir_from_path (fn));
2047 autostring file_n(get_file_from_path(fn));
2048 autostring rel_n (get_absolute_dir(dir_n, abs_tpd_dir));
2049 autostring abs_n (compose_path_name(rel_n, file_n));
2050
2051 if (local_argc == 0) {
2052 // We are being invoked recursively, for a referenced TPD.
2053 // Do not symlink; just return absolute paths to the files.
2054 if (*fn == '/') {
2055 if (*p_cflag) {
2056 // compose with workdir
2057 new_argv[n] = compose_path_name(abs_workdir, file_n);
2058 } else {
2059 // it's an absolute path, copy verbatim
2060 new_argv[n] = mcopystr(fn); // fn will be destroyed, pass a copy
2061 }
2062 }
2063 else { // relative path
2064 if (*p_cflag) {
2065 // compose with workdir
2066 new_argv[n] = compose_path_name(abs_workdir, file_n);
2067 // Do not call file_n.extract() : the composed path will be returned,
2068 // its component will need to be deallocated here.
2069 }
2070 else {
2071 // compose with tpd dir
2072 new_argv[n] = const_cast<char*>(abs_n.extract());
2073 }
2074 }
2075 }
2076 else { // we are processing the top-level TPD
2077#ifndef MINGW
2078 if (!*p_Pflag) {
2079 int fd = open(abs_n, O_RDONLY);
2080 if (fd >= 0) { // successfully opened
2081 close(fd);
2082 if (output_file) {
2083 file_n = compose_path_name(output_file, file_n);
2084 }
2085//TODO ! compose with output_file
2086 // save into list: add symlink data to the end of list
2087 if (create_symlink_list) {
2088 // go to last element
2089 struct string2_list* last_elem = create_symlink_list;
2090 while (last_elem->next) last_elem = last_elem->next;
2091 // add strings to last element if empty or create new last element and add it to that
2092 if (last_elem->str1) {
2093 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
2094 last_elem = last_elem->next;
2095 last_elem->next = NULL;
2096 }
2097 last_elem->str1 = mcopystr(abs_n);
2098 last_elem->str2 = mcopystr(file_n);
2099 }
2100 }
2101 else {
2102 ERROR("%s does not exist", (const char*)abs_n);
2103 }
2104 }
2105#endif
2106 if (*p_Pflag) {
2107 if (*p_aflag) {
2108 puts((const char *)abs_n);
2109 } else {
2110 autostring dir_part(get_dir_from_path(abs_n));
2111 autostring file_part(get_file_from_path(abs_n));
2112 autostring rel_dir_part(get_relative_dir((const char *)dir_part, file_list_path ? file_list_path : (const char *)abs_tpd_dir));
2113 autostring rel_dir_file_part(compose_path_name((const char *)rel_dir_part, (const char *)file_part));
2114 puts((const char *)rel_dir_file_part);
2115 }
2116 }
2117 new_argv[n] = const_cast<char *>(file_n.extract());
2118 }
2119 }
2120 // Print the TPD too.
2121 if (*p_Pflag) {
2122 autostring dir_part(get_dir_from_path(p_tpd_name));
2123 autostring file_part(get_file_from_path(p_tpd_name));
2124 if (*p_aflag) {
2125 puts((const char *)abs_tpd_name);
2126 } else {
2127 autostring rel_dir_part(get_relative_dir(dir_part, file_list_path ? file_list_path : abs_tpd_dir));
2128 autostring rel_dir_file_part(compose_path_name(rel_dir_part, file_part));
2129 const char *rel_tpd_name = (const char *)rel_dir_file_part;
2130 puts(rel_tpd_name);
2131 }
2132 }
2133
2134 // base_files from referenced projects
2135 for (size_t bf = 0, bs = base_files.size(); bf < bs; ++bf, ++n) {
2136 new_argv[n] = base_files[bf];
2137 }
2138 base_files.clear(); // string ownership transfered
2139
2140 // Then, copy the filenames from the command line.
2141 for (int a = *p_optind; a < *p_argc; ++a, ++n) {
2142 // String may be from main's argv; copy to the heap.
2143 new_argv[n] = mcopystr((*p_argv)[a]);
2144 }
2145
2146 if (local_argc > 0) { // it is the outermost call
2147 clear_seen_tpd_files(seen_tpd_files);
2148 }
2149 // replace argv
2150 *p_argv = new_argv;
2151 *p_argc = new_argc;
2152 *p_optind = 0;
2153
2154 // finally...
2155 for (size_t i = 0, e = files.size(); i < e; ++i) {
2156 Free(const_cast<char*>(files.get_nth_elem(i)));
2157 }
2158 files.clear();
2159
2160 for (size_t i = 0, e = folders.size(); i < e; ++i) {
2161 Free(const_cast<char*>(folders.get_nth_elem(i)));
2162 }
2163 folders.clear();
2164
2165 excluded_files.clear();
2166 excluded_folders.clear();
2167 path_vars.clear();
2168
2169 xmlCleanupParser();
2170 // ifdef debug
2171 xmlMemoryDump();
af710487 2172 return result;
970ed795 2173}
This page took 0.106917 seconds and 5 git commands to generate.