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