Sync with 5.4.2
[deliverable/titan.core.git] / compiler2 / xpather.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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"
32 #include "ProjectGenHelper.hh"
33 #include "../common/path.h"
34 #include "ttcn3/ttcn3_preparser.h"
35 #include "asn1/asn1_preparser.h"
36
37 // in makefile.c
38 void ERROR (const char *fmt, ...);
39 void WARNING(const char *fmt, ...);
40 void NOTIFY (const char *fmt, ...);
41 void DEBUG (const char *fmt, ...);
42
43 // for vector and map
44 void fatal_error(const char * filename, int lineno, const char * fmt, ...)
45 __attribute__ ((__format__ (__printf__, 3, 4), __noreturn__));
46
47 void 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
58 ProjectGenHelper& projGenHelper = ProjectGenHelper::Instance();
59
60 /// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
61 xmlXPathObjectPtr 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
75 class XmlDoc {
76 public:
77 explicit XmlDoc(xmlDocPtr p) : doc_(p) {}
78 ~XmlDoc() {
79 if (doc_ != NULL) xmlFreeDoc(doc_);
80 }
81 operator xmlDocPtr() const { return doc_; }
82 private:
83 xmlDocPtr doc_;
84 };
85
86 class XPathContext {
87 public:
88 explicit XPathContext(xmlXPathContextPtr c) : ctx_(c) {}
89 ~XPathContext() {
90 if (ctx_ != NULL) xmlXPathFreeContext(ctx_);
91 }
92 operator xmlXPathContextPtr() const { return ctx_; }
93 private:
94 xmlXPathContextPtr ctx_;
95 };
96
97 class XPathObject {
98 public:
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_; }
105 private:
106 xmlXPathObjectPtr xpo_;
107 };
108
109 //------------------------------------------------------------------
110 /// compare-by-content wrapper of a plain C string
111 struct cstring {
112 explicit cstring(const char *s) : str(s) {}
113 void destroy() const;
114 operator const char*() const { return str; }
115 protected:
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
121 void cstring::destroy() const {
122 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
123 }
124
125 boolean operator<(const cstring& l, const cstring& r) {
126 return strcmp(l.str, r.str) < 0;
127 }
128
129 boolean operator==(const cstring& l, const cstring& r) {
130 return strcmp(l.str, r.str) == 0;
131 }
132
133 /// RAII for C string
134 struct 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 }
153 private:
154 autostring(const autostring&);
155 autostring& operator=(const autostring&);
156 };
157
158
159 bool 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 */
211 void 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
226 extern "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
252 extern "C" string_list* getExternalLibPaths(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.getExternalLibSearchPaths(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
278 extern "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
300 extern "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
343 extern "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
351 extern "C" void erase_libs() {
352 projGenHelper.cleanUp();
353 }
354
355 extern "C" void print_libs() {
356 projGenHelper.print();
357 }
358
359
360 extern "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
370 extern "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
379 extern "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
389 extern "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
397 extern "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
404 extern "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
414 extern "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
428 extern "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
444 extern "C" boolean isTtcn3ModuleInLibrary(const char* moduleName)
445 {
446 if (!projGenHelper.getZflag()) return FALSE;
447 return (boolean)projGenHelper.isTtcn3ModuleInLibrary(moduleName);
448 }
449
450 extern "C" boolean isAsn1ModuleInLibrary(const char* moduleName)
451 {
452 if (!projGenHelper.getZflag()) return FALSE;
453 return (boolean)projGenHelper.isAsn1ModuleInLibrary(moduleName);
454 }
455
456 extern "C" boolean isSourceFileInLibrary(const char* fileName)
457 {
458 if (!projGenHelper.getZflag()) return FALSE;
459 return (boolean)projGenHelper.isSourceFileInLibrary(fileName);
460 }
461
462 extern "C" boolean isHeaderFileInLibrary(const char* fileName)
463 {
464 if (!projGenHelper.getZflag()) return FALSE;
465 return (boolean)projGenHelper.isHeaderFileInLibrary(fileName);
466 }
467
468 extern "C" boolean isTtcnPPFileInLibrary(const char* fileName)
469 {
470 if (!projGenHelper.getZflag()) return FALSE;
471 return (boolean)projGenHelper.isTtcnPPFileInLibrary(fileName);
472 }
473
474
475 extern "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
485 void 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
510 // data structures and functions to manage excluded folders/files
511
512 map<cstring, const char> excluded_files;
513
514 boolean 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;
519 }
520
521 vector<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 */
532 boolean 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.
549 char *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
577 void 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
590 static 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
600 const 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
608 static 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,
610 int *p_optind, char **p_ets_name, char **p_project_name,
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,
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,
620 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, 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,
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, struct string_list** profiled_file_list);
625
626 extern "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,
628 int *p_optind, char **p_ets_name, char **p_project_name,
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,
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,
638 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
639 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
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, struct string_list** profiled_file_list) {
643
644 map<cstring, int> seen_tpd_files;
645 projGenHelper.setZflag(*p_Zflag);
646 projGenHelper.setWflag(prefix_workdir);
647 projGenHelper.setHflag(*p_Hflag);
648
649 tpd_result success = process_tpd_internal(p_tpd_name,
650 actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, p_project_name,
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,
656 ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines,
657 prep_undefines, p_csflag, p_quflag, p_dsflag, cxxcompiler,
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, p_Mflag, solspeclibs, sol8speclibs,
661 linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep,
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, profiled_file_list);
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);
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().
696 static 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,
698 int *p_optind, char **p_ets_name, char **p_project_name,
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,
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,
708 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, boolean* p_Mflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
709 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
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, struct string_list** profiled_file_list)
713 {
714 tpd_result result = TPD_SUCCESS;
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));
728 if (NULL == (const char*)abs_tpd_dir) {
729 ERROR("absolute TPD directory could not be retrieved from %s", (const char*)tpd_dir);
730 return TPD_FAILED;
731 }
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
873 /////////////////////////////////////////////////////////////////////////////
874 {
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) {
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 }
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
959 autostring proj_abs_workdir;
960
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
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);
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));
999 proj_abs_workdir = mcopystr(*abs_work_dir_p);
1000 }
1001 }
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
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);
1049 excluded_files.add(aa, *p_project_name);
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);
1094 if (!is_excluded_file(cpath, *p_project_name) && !is_excluded_folder(path)) {
1095 // relativeURI wins over rawURI
1096 char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
1097 if (files.has_key(cpath)) {
1098 ERROR("A FileResource %s must be unique!", (const char*)cpath);
1099 }
1100 else {
1101 bool drop = false;
1102 const char* file_path = ruri;
1103 expstring_t rel_file_dir = get_dir_from_path(file_path);
1104 expstring_t file_name = get_file_from_path(file_path);
1105 expstring_t abs_dir_path = get_absolute_dir(rel_file_dir, abs_tpd_dir);
1106 expstring_t abs_file_name = compose_path_name(abs_dir_path, file_name);
1107 if (abs_file_name != NULL) {
1108 if (get_path_status(abs_file_name) == PS_FILE) {
1109 FILE *fp = fopen(abs_file_name, "r");
1110 if (fp != NULL) {
1111 char* ttcn3_module_name;
1112 if (is_ttcn3_module(abs_file_name, fp, &ttcn3_module_name)) {
1113 projGenHelper.addTtcn3ModuleToProject(*p_project_name, ttcn3_module_name);
1114 }
1115 Free(ttcn3_module_name);
1116 char* asn1_module_name;
1117 if (is_asn1_module(abs_file_name, fp, &asn1_module_name)) {
1118 projGenHelper.addAsn1ModuleToProject(*p_project_name, asn1_module_name);
1119 }
1120 Free(asn1_module_name);
1121 if (projGenHelper.isCPPSourceFile(file_name)) {
1122 projGenHelper.addUserSourceToProject(*p_project_name, file_name);
1123 }
1124 if (projGenHelper.isCPPHeaderFile(file_name)) {
1125 projGenHelper.addUserHeaderToProject(*p_project_name, file_name);
1126 }
1127 if (projGenHelper.isTtcnPPFile(file_name)) {
1128 projGenHelper.addTtcnPPToProject(*p_project_name, file_name);
1129 }
1130 }
1131 fclose(fp);
1132 }else {
1133 drop = true;
1134 ERROR("%s does not exist", abs_file_name);
1135 }
1136 }
1137 if(abs_dir_path != NULL && !drop){
1138 files.add(cpath, ruri); // relativeURI to the TPD location
1139 }else {
1140 cpath.destroy();
1141 result = TPD_FAILED;
1142 }
1143 { // set the *preprocess value if .ttcnpp file was found
1144 const size_t ttcnpp_extension_len = 7; // ".ttcnpp"
1145 const size_t ruri_len = strlen(ruri);
1146 if ( ruri_len>ttcnpp_extension_len && strcmp(ruri+(ruri_len-ttcnpp_extension_len),".ttcnpp")==0 ) {
1147 *preprocess = TRUE;
1148 }
1149 }
1150 Free(rel_file_dir);
1151 Free(file_name);
1152 Free(abs_dir_path);
1153 Free(abs_file_name);
1154 }
1155 }
1156 } // next FileResource
1157 }
1158
1159 // Check options
1160 xsdbool2boolean(xpathCtx, actcfg, "useAbsolutePath", p_aflag);
1161 xsdbool2boolean(xpathCtx, actcfg, "GNUMake", p_gflag);
1162 if (*p_Zflag) *p_lflag = FALSE;
1163 xsdbool2boolean(xpathCtx, actcfg, "dynamicLinking", p_lflag);
1164 xsdbool2boolean(xpathCtx, actcfg, "functiontestRuntime", p_Rflag);
1165 xsdbool2boolean(xpathCtx, actcfg, "singleMode", p_sflag);
1166 xsdbool2boolean(xpathCtx, actcfg, "codeSplitting", p_csflag);
1167 xsdbool2boolean(xpathCtx, actcfg, "quietly", p_quflag);
1168 xsdbool2boolean(xpathCtx, actcfg, "disableSubtypeChecking", p_dsflag);
1169 xsdbool2boolean(xpathCtx, actcfg, "disableBER", p_dbflag);
1170 xsdbool2boolean(xpathCtx, actcfg, "disableRAW", p_drflag);
1171 xsdbool2boolean(xpathCtx, actcfg, "disableTEXT", p_dtflag);
1172 xsdbool2boolean(xpathCtx, actcfg, "disableXER", p_dxflag);
1173 xsdbool2boolean(xpathCtx, actcfg, "disableJSON", p_djflag);
1174 xsdbool2boolean(xpathCtx, actcfg, "forceXERinASN.1", p_fxflag);
1175 xsdbool2boolean(xpathCtx, actcfg, "defaultasOmit", p_doflag);
1176 xsdbool2boolean(xpathCtx, actcfg, "gccMessageFormat", p_gfflag);
1177 xsdbool2boolean(xpathCtx, actcfg, "lineNumbersOnlyInMessages", p_lnflag);
1178 xsdbool2boolean(xpathCtx, actcfg, "includeSourceInfo", p_isflag);
1179 xsdbool2boolean(xpathCtx, actcfg, "addSourceLineInfo", p_asflag);
1180 xsdbool2boolean(xpathCtx, actcfg, "suppressWarnings", p_swflag);
1181 xsdbool2boolean(xpathCtx, actcfg, "outParamBoundness", p_Yflag); //not documented, obsolete
1182 xsdbool2boolean(xpathCtx, actcfg, "forceOldFuncOutParHandling", p_Yflag);
1183 xsdbool2boolean(xpathCtx, actcfg, "omitInValueList", p_Mflag);
1184
1185 projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1186 if (projDesc) projDesc->setLinkingStrategy(*p_lflag);
1187
1188 // Extract the "incremental dependencies" option
1189 {
1190 boolean incremental_deps = TRUE;
1191 xsdbool2boolean(xpathCtx, actcfg, "incrementalDependencyRefresh", &incremental_deps);
1192
1193 // For makefilegen, "Use GNU make" implies incremental deps by default,
1194 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
1195 // For Eclipse, incremental deps must be explicitly specified,
1196 // even if GNU make is being used.
1197
1198 if (incremental_deps) {
1199 if( !(*p_gflag) ) {
1200 WARNING("Incremental dependency ordered but it requires gnu make");
1201 }
1202 }
1203 else {
1204 if (*p_gflag) {
1205 // GNU make but no incremental deps
1206 *p_mflag = true;
1207 }
1208 }
1209 }
1210
1211 // Extract the default target option
1212 // if it is not defined as a command line argument
1213 if (!(*p_Lflag)) {
1214 expstring_t defTargetXpath = mprintf(
1215 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1216 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
1217 actcfg);
1218 XPathObject defTargetObj(run_xpath(xpathCtx, defTargetXpath));
1219 Free(defTargetXpath);
1220 if (defTargetObj->nodesetval && defTargetObj->nodesetval->nodeNr > 0) {
1221 const char* content = (const char*)defTargetObj->nodesetval->nodeTab[0]->content;
1222 if (!strcmp(content, "library")) {
1223 *p_Lflag = true;
1224 } else if (!strcmp(content, "executable")) {
1225 *p_Lflag = false;
1226 } else {
1227 ERROR("Unknown default target: '%s'."
1228 " The available targets are: 'executable', 'library'", content);
1229 }
1230 }
1231 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1232 if (projDesc) projDesc->setLibrary(*p_Lflag);
1233 }
1234
1235 // Executable name (don't care unless top-level invocation)
1236 if (local_argc != 0)
1237 {
1238 char *exeXpath = mprintf(
1239 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1240 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
1241 actcfg);
1242 XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
1243 Free(exeXpath);
1244 if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
1245 const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
1246 autostring target_exe_dir(get_dir_from_path(target_executable));
1247 autostring target_exe_file(get_file_from_path(target_executable));
1248 if (target_exe_dir!=NULL) { // if it's not only a file name
1249 if (get_path_status(target_exe_dir)==PS_NONEXISTENT) {
1250 if (strcmp(real_workdir,target_exe_dir)!=0) {
1251 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);
1252 }
1253 target_executable = target_exe_file;
1254 }
1255 }
1256 if (!*p_ets_name) { // Command line will win
1257 *p_ets_name = mcopystr(target_executable);
1258 }
1259 }
1260 }
1261
1262 // create an xml element for the currently processed project
1263 if (prj_graph_fp) {
1264 const char* prjNameStr = "???";
1265 XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
1266 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
1267 prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
1268 }
1269 autostring tpd_rel_dir(get_relative_dir(tpd_dir, NULL));
1270 autostring tpd_rel_path(compose_path_name(tpd_rel_dir, (const char*)tpd_filename));
1271 fprintf(prj_graph_fp, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr, (const char*)tpd_rel_path);
1272 XPathObject subprojects(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
1273 xmlNodeSetPtr nodes = subprojects->nodesetval;
1274 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1275 const char* refd_name = "???";
1276 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1277 refd_name = (const char*)nodes->nodeTab[i]->children->content;
1278 }
1279 fprintf(prj_graph_fp, "<reference name=\"%s\"/>\n", refd_name);
1280 }
1281 fprintf(prj_graph_fp, "</project>\n");
1282 }
1283
1284 // Tpd part of the MakefileSettings
1285 {
1286 //TTCN3preprocessorIncludes
1287 char *preincludeXpath = mprintf(
1288 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1289 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
1290 actcfg);
1291 XPathObject preincludeObj(run_xpath(xpathCtx, preincludeXpath));
1292 Free(preincludeXpath);
1293
1294 xmlNodeSetPtr nodes = preincludeObj->nodesetval;
1295
1296 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1297 char* content = (char*)preincludeObj->nodesetval->nodeTab[i]->content;
1298
1299 // add includes to the end of list
1300 if (ttcn3_prep_includes) {
1301 // go to last element
1302 struct string_list* last_elem = ttcn3_prep_includes;
1303 while (last_elem->next) last_elem = last_elem->next;
1304 // add string to last element if empty or create new last element and add it to that
1305 if (last_elem->str) {
1306 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1307 last_elem = last_elem->next;
1308 last_elem->next = NULL;
1309 }
1310 replacechar(&content);
1311 last_elem->str = content;
1312 }
1313 }
1314 }
1315 {
1316 //TTCN3preprocessorDefines
1317 char *ttcn3predefinesXpath = mprintf(
1318 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1319 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
1320 actcfg);
1321 XPathObject ttcn3predefinesObj(run_xpath(xpathCtx, ttcn3predefinesXpath));
1322 Free(ttcn3predefinesXpath);
1323
1324 xmlNodeSetPtr nodes = ttcn3predefinesObj->nodesetval;
1325
1326 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1327 const char* content = (const char*)ttcn3predefinesObj->nodesetval->nodeTab[i]->content;
1328
1329 // add includes to the end of list
1330 if (ttcn3_prep_defines) {
1331 // go to last element
1332 struct string_list* last_elem = ttcn3_prep_defines;
1333 while (last_elem->next) last_elem = last_elem->next;
1334 // add string to last element if empty or create new last element and add it to that
1335 if (last_elem->str) {
1336 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1337 last_elem = last_elem->next;
1338 last_elem->next = NULL;
1339 }
1340 last_elem->str = mcopystr(content);
1341 }
1342 }
1343 }
1344 {
1345 //TTCN3preprocessorUnDefines
1346 char *ttcn3preUndefinesXpath = mprintf(
1347 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1348 "/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()",
1349 actcfg);
1350 XPathObject ttcn3preUndefinesObj(run_xpath(xpathCtx, ttcn3preUndefinesXpath));
1351 Free(ttcn3preUndefinesXpath);
1352
1353 xmlNodeSetPtr nodes = ttcn3preUndefinesObj->nodesetval;
1354
1355 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1356 const char* content = (const char*)ttcn3preUndefinesObj->nodesetval->nodeTab[i]->content;
1357
1358 // add includes to the end of list
1359 if (ttcn3_prep_undefines) {
1360 // go to last element
1361 struct string_list* last_elem = ttcn3_prep_undefines;
1362 while (last_elem->next) last_elem = last_elem->next;
1363 // add string to last element if empty or create new last element and add it to that
1364 if (last_elem->str) {
1365 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1366 last_elem = last_elem->next;
1367 last_elem->next = NULL;
1368 }
1369 last_elem->str = mcopystr(content);
1370 }
1371 }
1372 }
1373
1374 {
1375 //preprocessorIncludes
1376 char *preincludesXpath = mprintf(
1377 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1378 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
1379 actcfg);
1380 XPathObject preincludesObj(run_xpath(xpathCtx, preincludesXpath));
1381 Free(preincludesXpath);
1382
1383 xmlNodeSetPtr nodes = preincludesObj->nodesetval;
1384
1385 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1386 char* content = (char*)preincludesObj->nodesetval->nodeTab[i]->content;
1387
1388 // add includes to the end of list
1389 if (prep_includes) {
1390 // go to last element
1391 struct string_list* last_elem = prep_includes;
1392 while (last_elem->next) last_elem = last_elem->next;
1393 // add string to last element if empty or create new last element and add it to that
1394 if (last_elem->str) {
1395 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1396 last_elem = last_elem->next;
1397 last_elem->next = NULL;
1398 }
1399 replacechar(&content);
1400 last_elem->str = content;
1401 }
1402 }
1403 }
1404 {
1405 //preprocessorDefines
1406 char *predefinesXpath = mprintf(
1407 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1408 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
1409 actcfg);
1410 XPathObject predefinesObj(run_xpath(xpathCtx, predefinesXpath));
1411 Free(predefinesXpath);
1412
1413 xmlNodeSetPtr nodes = predefinesObj->nodesetval;
1414
1415 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1416 const char* content = (const char*)predefinesObj->nodesetval->nodeTab[i]->content;
1417
1418 // add includes to the end of list
1419 if (prep_defines) {
1420 // go to last element
1421 struct string_list* last_elem = prep_defines;
1422 while (last_elem->next) last_elem = last_elem->next;
1423 // add string to last element if empty or create new last element and add it to that
1424 if (last_elem->str) {
1425 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1426 last_elem = last_elem->next;
1427 last_elem->next = NULL;
1428 }
1429 last_elem->str = mcopystr(content);
1430 }
1431 }
1432 }
1433 {
1434 //preprocessorUnDefines
1435 char *preUndefinesXpath = mprintf(
1436 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1437 "/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()",
1438 actcfg);
1439 XPathObject preUndefinesObj(run_xpath(xpathCtx, preUndefinesXpath));
1440 Free(preUndefinesXpath);
1441
1442 xmlNodeSetPtr nodes = preUndefinesObj->nodesetval;
1443
1444 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1445 const char* content = (const char*)preUndefinesObj->nodesetval->nodeTab[i]->content;
1446
1447 // add includes to the end of list
1448 if (prep_undefines) {
1449 // go to last element
1450 struct string_list* last_elem = prep_undefines;
1451 while (last_elem->next) last_elem = last_elem->next;
1452 // add string to last element if empty or create new last element and add it to that
1453 if (last_elem->str) {
1454 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1455 last_elem = last_elem->next;
1456 last_elem->next = NULL;
1457 }
1458 last_elem->str = mcopystr(content);
1459 }
1460 }
1461 }
1462 {
1463 char *cxxCompilerXpath = mprintf(
1464 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1465 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1466 actcfg);
1467 XPathObject cxxCompilerObj(run_xpath(xpathCtx, cxxCompilerXpath));
1468 Free(cxxCompilerXpath);
1469 xmlNodeSetPtr nodes = cxxCompilerObj->nodesetval;
1470 if (nodes) {
1471 *cxxcompiler = mcopystr((const char*)cxxCompilerObj->nodesetval->nodeTab[0]->content);
1472 }
1473 }
1474 {
1475 char *optLevelXpath = mprintf(
1476 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1477 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1478 actcfg);
1479 XPathObject optLevelObj(run_xpath(xpathCtx, optLevelXpath));
1480 Free(optLevelXpath);
1481 xmlNodeSetPtr nodes = optLevelObj->nodesetval;
1482 if (nodes) {
1483 *optlevel = mcopystr((const char*)optLevelObj->nodesetval->nodeTab[0]->content);
1484 }
1485 }
1486 {
1487 char *optFlagsXpath = mprintf(
1488 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1489 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1490 actcfg);
1491 XPathObject optFlagsObj(run_xpath(xpathCtx, optFlagsXpath));
1492 Free(optFlagsXpath);
1493 xmlNodeSetPtr nodes = optFlagsObj->nodesetval;
1494 if (nodes) {
1495 *optflags = mcopystr((const char*)optFlagsObj->nodesetval->nodeTab[0]->content);
1496 }
1497 }
1498 {
1499 //SolarisSpecificLibraries
1500 char *solspeclibXpath = mprintf(
1501 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1502 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1503 actcfg);
1504 XPathObject solspeclibObj(run_xpath(xpathCtx, solspeclibXpath));
1505 Free(solspeclibXpath);
1506
1507 xmlNodeSetPtr nodes = solspeclibObj->nodesetval;
1508
1509 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1510 char* content = (char*)solspeclibObj->nodesetval->nodeTab[i]->content;
1511
1512 // add includes to the end of list
1513 if (solspeclibs) {
1514 // go to last element
1515 struct string_list* last_elem =solspeclibs;
1516 while (last_elem->next) last_elem = last_elem->next;
1517 // add string to last element if empty or create new last element and add it to that
1518 if (last_elem->str) {
1519 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1520 last_elem = last_elem->next;
1521 last_elem->next = NULL;
1522 }
1523 replacechar(&content);
1524 last_elem->str = content;
1525 }
1526 }
1527 }
1528 {
1529 //Solaris8SpecificLibraries
1530 char *sol8speclibXpath = mprintf(
1531 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1532 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1533 actcfg);
1534 XPathObject sol8speclibObj(run_xpath(xpathCtx, sol8speclibXpath));
1535 Free(sol8speclibXpath);
1536
1537 xmlNodeSetPtr nodes = sol8speclibObj->nodesetval;
1538
1539 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1540 char* content = (char*)sol8speclibObj->nodesetval->nodeTab[i]->content;
1541
1542 // add includes to the end of list
1543 if (sol8speclibs) {
1544 // go to last element
1545 struct string_list* last_elem = sol8speclibs;
1546 while (last_elem->next) last_elem = last_elem->next;
1547 // add string to last element if empty or create new last element and add it to that
1548 if (last_elem->str) {
1549 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1550 last_elem = last_elem->next;
1551 last_elem->next = NULL;
1552 }
1553 replacechar(&content);
1554 last_elem->str = content;
1555 }
1556 }
1557 }
1558 {
1559 //LinuxSpecificLibraries
1560 char *linuxspeclibXpath = mprintf(
1561 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1562 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1563 actcfg);
1564 XPathObject linuxspeclibObj(run_xpath(xpathCtx, linuxspeclibXpath));
1565 Free(linuxspeclibXpath);
1566
1567 xmlNodeSetPtr nodes = linuxspeclibObj->nodesetval;
1568
1569 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1570 char* content = (char*)linuxspeclibObj->nodesetval->nodeTab[i]->content;
1571
1572 // add includes to the end of list
1573 if (linuxspeclibs) {
1574 // go to last element
1575 struct string_list* last_elem = linuxspeclibs;
1576 while (last_elem->next) last_elem = last_elem->next;
1577 // add string to last element if empty or create new last element and add it to that
1578 if (last_elem->str) {
1579 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1580 last_elem = last_elem->next;
1581 last_elem->next = NULL;
1582 }
1583 replacechar(&content);
1584 last_elem->str = content;
1585 }
1586 }
1587 }
1588 {
1589 //FreeBSDSpecificLibraries
1590 char *freebsdspeclibXpath = mprintf(
1591 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1592 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1593 actcfg);
1594 XPathObject freebsdspeclibObj(run_xpath(xpathCtx, freebsdspeclibXpath));
1595 Free(freebsdspeclibXpath);
1596
1597 xmlNodeSetPtr nodes = freebsdspeclibObj->nodesetval;
1598
1599 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1600 char* content = (char*)freebsdspeclibObj->nodesetval->nodeTab[i]->content;
1601
1602 // add includes to the end of list
1603 if (freebsdspeclibs) {
1604 // go to last element
1605 struct string_list* last_elem = freebsdspeclibs;
1606 while (last_elem->next) last_elem = last_elem->next;
1607 // add string to last element if empty or create new last element and add it to that
1608 if (last_elem->str) {
1609 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1610 last_elem = last_elem->next;
1611 last_elem->next = NULL;
1612 }
1613 replacechar(&content);
1614 last_elem->str = content;
1615 }
1616 }
1617 }
1618 {
1619 //Win32SpecificLibraries
1620 char *win32speclibXpath = mprintf(
1621 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1622 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1623 actcfg);
1624 XPathObject win32speclibObj(run_xpath(xpathCtx, win32speclibXpath));
1625 Free(win32speclibXpath);
1626
1627 xmlNodeSetPtr nodes = win32speclibObj->nodesetval;
1628
1629 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1630 char* content = (char*)win32speclibObj->nodesetval->nodeTab[i]->content;
1631
1632 // add includes to the end of list
1633 if (win32speclibs) {
1634 // go to last element
1635 struct string_list* last_elem = win32speclibs;
1636 while (last_elem->next) last_elem = last_elem->next;
1637 // add string to last element if empty or create new last element and add it to that
1638 if (last_elem->str) {
1639 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1640 last_elem = last_elem->next;
1641 last_elem->next = NULL;
1642 }
1643 replacechar(&content);
1644 last_elem->str = content;
1645 }
1646
1647 }
1648 }
1649 {
1650 //TTCN3preprocessor
1651 char *ttcn3preproc = mprintf(
1652 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1653 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1654 actcfg);
1655 XPathObject ttcn3preprocObj(run_xpath(xpathCtx, ttcn3preproc));
1656 Free(ttcn3preproc);
1657 xmlNodeSetPtr nodes = ttcn3preprocObj->nodesetval;
1658 if (nodes) {
1659 *ttcn3prep = mcopystr((const char*)ttcn3preprocObj->nodesetval->nodeTab[0]->content);
1660 }
1661 }
1662 {
1663 // additionalObjects
1664 char *additionalObjectsXpath = mprintf(
1665 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1666 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1667 actcfg);
1668 XPathObject additionalObjectsObj(run_xpath(xpathCtx, additionalObjectsXpath));
1669 Free(additionalObjectsXpath);
1670
1671 xmlNodeSetPtr nodes = additionalObjectsObj->nodesetval;
1672
1673 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1674 char* content = (char*)additionalObjectsObj->nodesetval->nodeTab[i]->content;
1675
1676 // add to the end of list
1677 if (additionalObjects) {
1678 // go to last element
1679 struct string_list* last_elem = additionalObjects;
1680 while (last_elem->next) last_elem = last_elem->next;
1681 // add string to last element if empty or create new last element and add it to that
1682 if (last_elem->str) {
1683 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1684 last_elem = last_elem->next;
1685 last_elem->next = NULL;
1686 }
1687 replacechar(&content);
1688 last_elem->str = content;
1689 }
1690 }
1691 }
1692 {
1693 //The project name needed the hierarchical projects
1694 char* prjNameStr = 0;
1695 char *prjNameStrXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()");
1696 XPathObject prjName(run_xpath(xpathCtx, prjNameStrXpath));
1697 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
1698 prjNameStr = (char*)prjName->nodesetval->nodeTab[0]->content;
1699 }
1700 Free(prjNameStrXpath);
1701 append_to_library_list (prjNameStr, xpathCtx, actcfg);
1702
1703 //linkerLibraries
1704 char *linkerlibsXpath = mprintf(
1705 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1706 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1707 actcfg);
1708 XPathObject linkerlibsObj(run_xpath(xpathCtx, linkerlibsXpath));
1709 Free(linkerlibsXpath);
1710
1711 xmlNodeSetPtr nodes = linkerlibsObj->nodesetval;
1712
1713 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1714 char* content = (char*)linkerlibsObj->nodesetval->nodeTab[i]->content;
1715
1716 // add includes to the end of list
1717 if (linkerlibs) {
1718 // go to last element
1719 struct string_list* last_elem = linkerlibs;
1720 while (last_elem->next) last_elem = last_elem->next;
1721 // add string to last element if empty or create new last element and add it to that
1722 if (last_elem->str) {
1723 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1724 last_elem = last_elem->next;
1725 last_elem->next = NULL;
1726 }
1727 replacechar(&content);
1728 last_elem->str = content;
1729
1730 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1731 if (projDesc) projDesc->addToLinkerLibs(last_elem->str);
1732 }
1733 }
1734 }
1735 {
1736 //linkerLibrarySearchPath
1737 char *linkerlibsearchXpath = mprintf(
1738 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1739 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1740 actcfg);
1741 XPathObject linkerlibsearchObj(run_xpath(xpathCtx, linkerlibsearchXpath));
1742 Free(linkerlibsearchXpath);
1743
1744 xmlNodeSetPtr nodes = linkerlibsearchObj->nodesetval;
1745
1746 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1747 char* content = (char*)linkerlibsearchObj->nodesetval->nodeTab[i]->content;
1748
1749 // add includes to the end of list
1750 if (linkerlibsearchp) {
1751 // go to last element
1752 struct string_list* last_elem = linkerlibsearchp;
1753 while (last_elem->next) last_elem = last_elem->next;
1754 // add string to last element if empty or create new last element and add it to that
1755 if (last_elem->str) {
1756 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1757 last_elem = last_elem->next;
1758 last_elem->next = NULL;
1759 }
1760 replacechar(&content);
1761 last_elem->str = content;
1762
1763 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1764 if (projDesc) projDesc->addToLibSearchPaths(last_elem->str);
1765 }
1766 }
1767 }
1768
1769 if (generatorCommandOutput && local_argc != 0) { // only in case of top-level invocation
1770 char* generatorCommandXpath = mprintf(
1771 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1772 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1773 actcfg);
1774 XPathObject generatorCommandObj(run_xpath(xpathCtx, generatorCommandXpath));
1775 Free(generatorCommandXpath);
1776 autostring generatorCommand;
1777 if (generatorCommandObj->nodesetval && generatorCommandObj->nodesetval->nodeNr > 0) {
1778 generatorCommand = mcopystr((const char*)generatorCommandObj->nodesetval->nodeTab[0]->content);
1779 // run the command and capture the output
1780 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand, (const char*)abs_tpd_name);
1781 FILE* gc_fp = popen(generatorCommand, "r");
1782 if (!gc_fp) {
1783 ERROR("Could not execute command `%s'", (const char*)generatorCommand);
1784 } else {
1785 char buff[1024];
1786 while (fgets(buff, sizeof(buff), gc_fp)!=NULL) {
1787 *generatorCommandOutput = mputstr(*generatorCommandOutput, buff);
1788 }
1789 pclose(gc_fp);
1790 }
1791 }
1792 }
1793
1794 if (target_placement_list && local_argc != 0) { // only in case of top-level invocation
1795 char* targetPlacementXpath = mprintf(
1796 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1797 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1798 actcfg);
1799 XPathObject targetPlacementObj(run_xpath(xpathCtx, targetPlacementXpath));
1800 Free(targetPlacementXpath);
1801 xmlNodeSetPtr nodes = targetPlacementObj->nodesetval;
1802 const char* targetName = NULL;
1803 const char* targetPlacement = NULL;
1804 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1805 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1806 targetName = (const char*)nodes->nodeTab[i]->children->content;
1807 }
1808 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"placement")) {
1809 targetPlacement = (const char*)nodes->nodeTab[i]->children->content;
1810 }
1811 if (targetName && targetPlacement) { // collected both
1812 if (target_placement_list) {
1813 // go to last element
1814 struct string2_list* last_elem = target_placement_list;
1815 while (last_elem->next) last_elem = last_elem->next;
1816 // add strings to last element if empty or create new last element and add it to that
1817 if (last_elem->str1) {
1818 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1819 last_elem = last_elem->next;
1820 last_elem->next = NULL;
1821 }
1822 last_elem->str1 = mcopystr(targetName);
1823 last_elem->str2 = mcopystr(targetPlacement);
1824 }
1825 targetName = targetPlacement = NULL; // forget both
1826 }
1827 }
1828 }
1829
1830 {
1831 // profiler file name
1832 char* profilerXpath = mprintf(
1833 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1834 "/ProjectProperties/MakefileSettings/profiledFileList", actcfg);
1835 XPathObject profiledFilesNameObj(run_xpath(xpathCtx, profilerXpath));
1836 Free(profilerXpath);
1837 xmlNodeSetPtr nodes = profiledFilesNameObj->nodesetval;
1838 if (nodes && nodes->nodeNr > 0) {
1839 const char *uri = 0, *path = 0, *raw = 0;
1840 for (xmlAttrPtr attr = nodes->nodeTab[0]->properties; attr; attr = attr->next) {
1841 if (!strcmp((const char*)attr->name, "projectRelativePath")) {
1842 path = (const char*)attr->children->content;
1843 }
1844 else if (!strcmp((const char*)attr->name, "relativeURI")) {
1845 uri = (const char*)attr->children->content;
1846 }
1847 else if (!strcmp((const char*)attr->name, "rawURI")) {
1848 raw = (const char*)attr->children->content;
1849 }
1850 else {
1851 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[0]->name);
1852 }
1853 } // next attribute
1854
1855 if (path == NULL) {
1856 ERROR("A profiledFileList must have a projectRelativePath");
1857 }
1858 else {
1859 if (uri == NULL && raw == NULL) {
1860 ERROR("A profiledFileList must have either relativeURI or rawURI");
1861 }
1862 else {
1863 cstring cpath(path);
1864 if (files.has_key(cpath)) {
1865 ERROR("profiledFileLists and FileResources must be unique!");
1866 }
1867 else {
1868 // add the file to the end of the list
1869 struct string_list* new_item = NULL;
1870 if (*profiled_file_list == NULL) {
1871 *profiled_file_list = (struct string_list*)Malloc(sizeof(struct string_list));
1872 new_item = *profiled_file_list;
1873 }
1874 else {
1875 new_item = *profiled_file_list;
1876 while(new_item->next != NULL) {
1877 new_item = new_item->next;
1878 }
1879 new_item->next = (struct string_list*)Malloc(sizeof(struct string_list));
1880 new_item = new_item->next;
1881 }
1882 new_item->str = mcopystr(path);
1883 new_item->next = NULL;
1884
1885 // add the file to the map of files to be copied to the working directory
1886 char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
1887 files.add(cpath, ruri);
1888 }
1889 }
1890 }
1891 }
1892 }
1893
1894 // collect the required configurations
1895 {
1896 if (required_configs) {
1897 char* cfgReqsXpath(mprintf(
1898 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1899 "/ProjectProperties/ConfigurationRequirements/configurationRequirement",
1900 actcfg));
1901 XPathObject reqcfgObjects(run_xpath(xpathCtx, cfgReqsXpath));
1902 Free (cfgReqsXpath);
1903 xmlNodeSetPtr configs = reqcfgObjects->nodesetval;
1904 if (configs) for (int i = 0; i < configs->nodeNr; ++i) {
1905 xmlNodePtr curNodePtr = configs->nodeTab[i]->children;
1906 const char* projectName = NULL;
1907 const char* reqConfig = NULL;
1908 while(curNodePtr) {
1909 if (!strcmp((const char*)curNodePtr->name, "projectName")) {
1910 projectName = (const char*)curNodePtr->children->content;
1911 }
1912 if (!strcmp((const char*)curNodePtr->name, "rerquiredConfiguration") || // backward compatibility
1913 !strcmp((const char*)curNodePtr->name, "requiredConfiguration")) {
1914 reqConfig = (const char*)curNodePtr->children->content;
1915 }
1916 curNodePtr = curNodePtr->next;
1917 }
1918 struct string2_list* last_elem = required_configs;
1919 bool duplicate = false;
1920 while (last_elem->next) {
1921 if (!strcmp(last_elem->str1, projectName) && !strcmp(last_elem->str2, reqConfig)) {
1922 duplicate = true;
1923 }
1924 else if (!strcmp(last_elem->str1, projectName) && strcmp(last_elem->str2, reqConfig)) {
1925 ERROR("Required configuration is inconsistent : Project '%s' cannot have 2 "
1926 "different configuration '%s' '%s'",
1927 last_elem->str1, last_elem->str2, reqConfig);
1928 result = TPD_FAILED;
1929 }
1930 last_elem = last_elem->next;
1931 }
1932 // add string to last element if empty or create new last element and add it to that
1933 if (last_elem->str1 && !duplicate) {
1934 if (strcmp(last_elem->str1, projectName) || strcmp(last_elem->str2, reqConfig)) {
1935 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1936 last_elem = last_elem->next;
1937 last_elem->next = NULL;
1938 }
1939 else {
1940 duplicate = true;
1941 }
1942 }
1943 if (!duplicate) {
1944 last_elem->str1 = mcopystr(projectName);
1945 last_elem->str2 = mcopystr(reqConfig);
1946 }
1947 }
1948 }
1949 }
1950
1951 // Referenced projects
1952 {
1953 XPathObject subprojects(run_xpath(xpathCtx,
1954 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::*"));
1955 xmlNodeSetPtr nodes = subprojects->nodesetval;
1956 const char *name = NULL, *projectLocationURI = NULL;
1957 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1958 // FIXME: this assumes every ReferencedProject has name and URI.
1959 // This is not necessarily so if the referenced project was closed
1960 // when the project was exported to TPD.
1961 // Luckily, the name from the closed project will be overwritten
1962 // by the name from the next ReferencedProject. However, if some pervert
1963 // changes the next ReferencedProject to have the projectLocationURI
1964 // as the first attribute, it will be joined to the name
1965 // of the previous, closed, ReferencedProject.
1966 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1967 name = (const char*)nodes->nodeTab[i]->children->content;
1968 }
1969 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"projectLocationURI")) {
1970 projectLocationURI = (const char*)nodes->nodeTab[i]->children->content;
1971 }
1972
1973 if (name && projectLocationURI) { // collected both
1974 // see if there is a specified configuration for the project
1975
1976 ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name);
1977 if (projDesc) projDesc->addToReferencedProjects(name);
1978
1979 const char *my_actcfg = NULL;
1980 int my_argc = 0;
1981 char *my_args[] = { NULL };
1982 char **my_argv = my_args + 0;
1983 int my_optind = 0;
1984 boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down
1985 my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, my_Zflag = *p_Zflag, my_Hflag = *p_Hflag,
1986 my_sflag = 0, my_Lflag = 0, my_lflag = 0, my_mflag = 0, my_csflag = 0,
1987 my_quflag = 0, my_dsflag = 0, my_dbflag = 0, my_drflag = 0,
1988 my_dtflag = 0, my_dxflag = 0, my_djflag = 0, my_fxflag = 0, my_doflag = 0,
1989 my_gfflag = 0, my_lnflag = 0, my_isflag = 0, my_asflag = 0,
1990 my_swflag = 0, my_Yflag = 0, my_Mflag = *p_Mflag;
1991
1992 char *my_ets = NULL;
1993 char *my_proj_name = NULL;
1994 autostring abs_projectLocationURI(
1995 compose_path_name(abs_tpd_dir, projectLocationURI));
1996
1997 char* sub_proj_abs_work_dir = NULL;
1998
1999 tpd_result success = process_tpd_internal((const char*)abs_projectLocationURI,
2000 my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets, &my_proj_name,
2001 &my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag,
2002 &my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir,
2003 sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines,
2004 prep_includes, prep_defines, prep_undefines, &my_csflag,
2005 &my_quflag, &my_dsflag, cxxcompiler, optlevel, optflags, &my_dbflag, &my_drflag,
2006 &my_dtflag, &my_dxflag, &my_djflag, &my_fxflag, &my_doflag,
2007 &my_gfflag, &my_lnflag, &my_isflag, &my_asflag, &my_swflag, &my_Yflag, &my_Mflag,
2008 solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs,
2009 ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, &my_Zflag,
2010 &my_Hflag, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files, required_configs, profiled_file_list);
2011
2012 autostring sub_proj_abs_work_dir_as(sub_proj_abs_work_dir); // ?!
2013
2014 if (success == TPD_SUCCESS) {
2015 my_actcfg = get_act_config(required_configs, my_proj_name);
2016 if (recursive) { // call ttcn3_makefilegen on referenced project's tpd file
2017 // -r is not needed any more because top level process traverses all projects recursively
2018 expstring_t command = mprintf("%s -cVD", program_name);
2019 if (force_overwrite) command = mputc(command, 'f');
2020 if (prefix_workdir) command = mputc(command, 'W');
2021 if (*p_gflag) command = mputc(command, 'g');
2022 if (*p_sflag) command = mputc(command, 's');
2023 if (*p_aflag) command = mputc(command, 'a');
2024 if (*p_Rflag) command = mputc(command, 'R');
2025 if (*p_lflag) command = mputc(command, 'l');
2026 if (*p_mflag) command = mputc(command, 'm');
2027 if (*p_Zflag) command = mputc(command, 'Z');
2028 if (*p_Hflag) command = mputc(command, 'H');
2029 command = mputstr(command, " -t ");
2030 command = mputstr(command, (const char*)abs_projectLocationURI);
2031 if (my_actcfg) {
2032 command = mputstr(command, " -b ");
2033 command = mputstr(command, my_actcfg);
2034 }
2035
2036 autostring sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI));
2037 const char * sub_proj_effective_work_dir = sub_proj_abs_work_dir ? sub_proj_abs_work_dir : (const char*)sub_tpd_dir;
2038 if (!gen_only_top_level) {
2039 if (run_command_list) {
2040 // go to last element
2041 struct string2_list* last_elem = run_command_list;
2042 while (last_elem->next) last_elem = last_elem->next;
2043 // add strings to last element if empty or create new last element and add it to that
2044 if (last_elem->str1 || last_elem->str2) {
2045 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
2046 last_elem = last_elem->next;
2047 last_elem->next = NULL;
2048 }
2049 last_elem->str1 = mcopystr(sub_proj_effective_work_dir);
2050 last_elem->str2 = command;
2051 } else {
2052 ERROR("Internal error: cannot add command to list");
2053 }
2054 }
2055 // add working dir to the end of list
2056 if (sub_project_dirs) {
2057 // go to last element
2058 struct string_list* last_elem = sub_project_dirs;
2059 while (last_elem->next) last_elem = last_elem->next;
2060 // add string to last element if empty or create new last element and add it to that
2061 if (last_elem->str) {
2062 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
2063 last_elem = last_elem->next;
2064 last_elem->next = NULL;
2065 }
2066 autostring cwd_as(get_working_dir());
2067 last_elem->str = (*p_aflag) ? mcopystr(sub_proj_effective_work_dir) : get_relative_dir(sub_proj_effective_work_dir, (const char*)cwd_as);
2068 }
2069 }
2070
2071 for (int z = 0; z < my_argc; ++z) {
2072 if (*p_cflag) {
2073 // central storage, keep in separate container
2074 base_files.add(my_argv[z]); // string was allocated with new
2075 }
2076 else {
2077 const cstring tmp(my_argv[z]);
2078 if (!files.has_key(tmp)){
2079 files.add(tmp, my_argv[z]);
2080 } else {
2081 Free(my_argv[z]);
2082 }
2083 }
2084 }
2085
2086 Free(my_argv); // free the array; we keep the pointers
2087 Free(my_ets);
2088 Free(my_proj_name);
2089 }
2090 else if (success == TPD_FAILED) {
2091 ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
2092 result = TPD_FAILED;
2093 }
2094 // else TPD_SKIPPED, keep quiet
2095
2096 name = projectLocationURI = NULL; // forget both
2097 }
2098 } // next referenced project
2099 }
2100
2101 if (output_file) {
2102 if (get_path_status(output_file) == PS_DIRECTORY) {
2103 // points to existing dir; use as-is
2104 }
2105 else { // we assume it points to a file: not our problem
2106 output_file = NULL;
2107 }
2108 }
2109
2110 // (argc - optind) is the number of non-option arguments (assumed to be files)
2111 // given on the command line.
2112 int new_argc = local_argc - local_optind + files.size() + base_files.size();
2113 char ** new_argv = (char**)Malloc(sizeof(char*) * new_argc);
2114
2115 int n = 0;
2116
2117 // First, copy the filenames gathered from the TPD
2118 //
2119 // We symlink the files into the working directory
2120 // and pass only the filename to the makefile generator
2121 for (int nf = files.size(); n < nf; ++n) {
2122 const char *fn = files.get_nth_elem(n); // relativeURI to the TPD location
2123 autostring dir_n (get_dir_from_path (fn));
2124 autostring file_n(get_file_from_path(fn));
2125 autostring rel_n (get_absolute_dir(dir_n, abs_tpd_dir));
2126 autostring abs_n (compose_path_name(rel_n, file_n));
2127
2128 if (local_argc == 0) {
2129 // We are being invoked recursively, for a referenced TPD.
2130 // Do not symlink; just return absolute paths to the files.
2131 if (*fn == '/') {
2132 if (*p_cflag) {
2133 // compose with workdir
2134 new_argv[n] = compose_path_name(abs_workdir, file_n);
2135 } else {
2136 // it's an absolute path, copy verbatim
2137 new_argv[n] = mcopystr(fn); // fn will be destroyed, pass a copy
2138 }
2139 }
2140 else { // relative path
2141 if (*p_cflag) {
2142 // compose with workdir
2143 new_argv[n] = compose_path_name(abs_workdir, file_n);
2144 // Do not call file_n.extract() : the composed path will be returned,
2145 // its component will need to be deallocated here.
2146 }
2147 else {
2148 // compose with tpd dir
2149 new_argv[n] = const_cast<char*>(abs_n.extract());
2150 }
2151 }
2152 }
2153 else { // we are processing the top-level TPD
2154 #ifndef MINGW
2155 if (!*p_Pflag) {
2156 int fd = open(abs_n, O_RDONLY);
2157 if (fd >= 0) { // successfully opened
2158 close(fd);
2159 if (output_file) {
2160 file_n = compose_path_name(output_file, file_n);
2161 }
2162 //TODO ! compose with output_file
2163 // save into list: add symlink data to the end of list
2164 if (create_symlink_list) {
2165 // go to last element
2166 struct string2_list* last_elem = create_symlink_list;
2167 while (last_elem->next) last_elem = last_elem->next;
2168 // add strings to last element if empty or create new last element and add it to that
2169 if (last_elem->str1) {
2170 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
2171 last_elem = last_elem->next;
2172 last_elem->next = NULL;
2173 }
2174 last_elem->str1 = mcopystr(abs_n);
2175 last_elem->str2 = mcopystr(file_n);
2176 }
2177 }
2178 else {
2179 ERROR("%s does not exist", (const char*)abs_n);
2180 }
2181 }
2182 #endif
2183 if (*p_Pflag) {
2184 if (*p_aflag) {
2185 puts((const char *)abs_n);
2186 } else {
2187 autostring dir_part(get_dir_from_path(abs_n));
2188 autostring file_part(get_file_from_path(abs_n));
2189 autostring rel_dir_part(get_relative_dir((const char *)dir_part, file_list_path ? file_list_path : (const char *)abs_tpd_dir));
2190 autostring rel_dir_file_part(compose_path_name((const char *)rel_dir_part, (const char *)file_part));
2191 puts((const char *)rel_dir_file_part);
2192 }
2193 }
2194 new_argv[n] = const_cast<char *>(file_n.extract());
2195 }
2196 }
2197 // Print the TPD too.
2198 if (*p_Pflag) {
2199 autostring dir_part(get_dir_from_path(p_tpd_name));
2200 autostring file_part(get_file_from_path(p_tpd_name));
2201 if (*p_aflag) {
2202 puts((const char *)abs_tpd_name);
2203 } else {
2204 autostring rel_dir_part(get_relative_dir(dir_part, file_list_path ? file_list_path : abs_tpd_dir));
2205 autostring rel_dir_file_part(compose_path_name(rel_dir_part, file_part));
2206 const char *rel_tpd_name = (const char *)rel_dir_file_part;
2207 puts(rel_tpd_name);
2208 }
2209 }
2210
2211 // base_files from referenced projects
2212 for (size_t bf = 0, bs = base_files.size(); bf < bs; ++bf, ++n) {
2213 new_argv[n] = base_files[bf];
2214 }
2215 base_files.clear(); // string ownership transfered
2216
2217 // Then, copy the filenames from the command line.
2218 for (int a = *p_optind; a < *p_argc; ++a, ++n) {
2219 // String may be from main's argv; copy to the heap.
2220 new_argv[n] = mcopystr((*p_argv)[a]);
2221 }
2222
2223 if (local_argc > 0) { // it is the outermost call
2224 clear_seen_tpd_files(seen_tpd_files);
2225 }
2226 // replace argv
2227 *p_argv = new_argv;
2228 *p_argc = new_argc;
2229 *p_optind = 0;
2230
2231 // finally...
2232 for (size_t i = 0, e = files.size(); i < e; ++i) {
2233 Free(const_cast<char*>(files.get_nth_elem(i)));
2234 }
2235 files.clear();
2236
2237 for (size_t i = 0, e = folders.size(); i < e; ++i) {
2238 Free(const_cast<char*>(folders.get_nth_elem(i)));
2239 }
2240 folders.clear();
2241
2242 excluded_files.clear();
2243 excluded_folders.clear();
2244 path_vars.clear();
2245
2246 xmlCleanupParser();
2247 // ifdef debug
2248 xmlMemoryDump();
2249 return result;
2250 }
This page took 0.111267 seconds and 5 git commands to generate.