14c15a6de426974da68545eadfd5222ce30f27e0
[deliverable/titan.core.git] / compiler2 / xpather.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "xpather.h"
9
10 #include <string.h>
11 #include <assert.h>
12 #include <unistd.h>
13 #include <limits.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <fcntl.h>
18 #include <string>
19
20 #include <libxml/parser.h>
21 #include <libxml/tree.h>
22 #include <libxml/xpath.h>
23
24 #define LIBXML_SCHEMAS_ENABLED
25 #include <libxml/xmlschemastypes.h>
26
27 #include "../common/memory.h"
28 #include "vector.hh"
29 // Do _NOT_ #include "string.hh", it drags in ustring.o, common/Quadruple.o,
30 // Int.o, ttcn3/PatternString.o, and then the entire AST :(
31 #include "map.hh"
32 #include "../common/path.h"
33
34 // in makefile.c
35 void ERROR (const char *fmt, ...);
36 void WARNING(const char *fmt, ...);
37 void NOTIFY (const char *fmt, ...);
38 void DEBUG (const char *fmt, ...);
39
40 // for vector and map
41 void fatal_error(const char * filename, int lineno, const char * fmt, ...)
42 __attribute__ ((__format__ (__printf__, 3, 4), __noreturn__));
43
44 void fatal_error(const char * filename, int lineno, const char * fmt, ...)
45 {
46 fputs(filename, stderr);
47 fprintf(stderr, ":%d: ", lineno);
48 va_list va;
49 va_start(va, fmt);
50 vfprintf(stderr, fmt, va);
51 va_end(va);
52 abort();
53 }
54
55 /// Run an XPath query and return an xmlXPathObjectPtr, which must be freed
56 xmlXPathObjectPtr run_xpath(xmlXPathContextPtr xpathCtx, const char *xpathExpr)
57 {
58 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(
59 (const xmlChar *)xpathExpr, xpathCtx);
60 if(xpathObj == NULL) {
61 fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
62 return 0;
63 }
64
65 return xpathObj;
66 }
67
68 // RAII classes
69
70 class XmlDoc {
71 public:
72 explicit XmlDoc(xmlDocPtr p) : doc_(p) {}
73 ~XmlDoc() {
74 if (doc_ != NULL) xmlFreeDoc(doc_);
75 }
76 operator xmlDocPtr() const { return doc_; }
77 private:
78 xmlDocPtr doc_;
79 };
80
81 class XPathContext {
82 public:
83 explicit XPathContext(xmlXPathContextPtr c) : ctx_(c) {}
84 ~XPathContext() {
85 if (ctx_ != NULL) xmlXPathFreeContext(ctx_);
86 }
87 operator xmlXPathContextPtr() const { return ctx_; }
88 private:
89 xmlXPathContextPtr ctx_;
90 };
91
92 class XPathObject {
93 public:
94 explicit XPathObject(xmlXPathObjectPtr o) : xpo_(o) {}
95 ~XPathObject() {
96 if (xpo_ != NULL) xmlXPathFreeObject(xpo_);
97 }
98 operator xmlXPathObjectPtr() const { return xpo_; }
99 xmlXPathObjectPtr operator->() const { return xpo_; }
100 private:
101 xmlXPathObjectPtr xpo_;
102 };
103
104 //------------------------------------------------------------------
105 /// compare-by-content wrapper of a plain C string
106 struct cstring {
107 explicit cstring(const char *s) : str(s) {}
108 void destroy() const;
109 operator const char*() const { return str; }
110 protected:
111 const char *str;
112 friend boolean operator<(const cstring& l, const cstring& r);
113 friend boolean operator==(const cstring& l, const cstring& r);
114 };
115
116 void cstring::destroy() const {
117 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
118 }
119
120 boolean operator<(const cstring& l, const cstring& r) {
121 return strcmp(l.str, r.str) < 0;
122 }
123
124 boolean operator==(const cstring& l, const cstring& r) {
125 return strcmp(l.str, r.str) == 0;
126 }
127
128 /// RAII for C string
129 struct autostring : public cstring {
130 /// Constructor; takes over ownership
131 explicit autostring(const char *s = 0) : cstring(s) {}
132 ~autostring() {
133 // He who can destroy a thing, controls that thing -- Paul Muad'Dib
134 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
135 }
136 /// %Assignment; takes over ownership
137 const autostring& operator=(const char *s) {
138 Free(const_cast<char*>(str)); // assumes valid pointer or NULL
139 str = s;
140 return *this;
141 }
142 /// Relinquish ownership
143 const char *extract() {
144 const char *retval = str;
145 str = 0;
146 return retval;
147 }
148 private:
149 autostring(const autostring&);
150 autostring& operator=(const autostring&);
151 };
152
153
154 bool validate_tpd(const XmlDoc& xml_doc, const char* tpd_file_name, const char* xsd_file_name)
155 {
156 xmlLineNumbersDefault(1);
157
158 xmlSchemaParserCtxtPtr ctxt = xmlSchemaNewParserCtxt(xsd_file_name);
159 if (ctxt==NULL) {
160 ERROR("Unable to create xsd context for xsd file `%s'", xsd_file_name);
161 return false;
162 }
163 xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc)fprintf, (xmlSchemaValidityWarningFunc)fprintf, stderr);
164
165 xmlSchemaPtr schema = xmlSchemaParse(ctxt);
166 if (schema==NULL) {
167 ERROR("Unable to parse xsd file `%s'", xsd_file_name);
168 xmlSchemaFreeParserCtxt(ctxt);
169 return false;
170 }
171
172 xmlSchemaValidCtxtPtr xsd = xmlSchemaNewValidCtxt(schema);
173 if (xsd==NULL) {
174 ERROR("Schema validation error for xsd file `%s'", xsd_file_name);
175 xmlSchemaFree(schema);
176 xmlSchemaFreeParserCtxt(ctxt);
177 return false;
178 }
179 xmlSchemaSetValidErrors(xsd, (xmlSchemaValidityErrorFunc) fprintf, (xmlSchemaValidityWarningFunc) fprintf, stderr);
180
181 int ret = xmlSchemaValidateDoc(xsd, xml_doc);
182
183 xmlSchemaFreeValidCtxt(xsd);
184 xmlSchemaFree(schema);
185 xmlSchemaFreeParserCtxt(ctxt);
186 xmlSchemaCleanupTypes();
187
188 if (ret==0) {
189 return true; // successful validation
190 } else if (ret>0) {
191 ERROR("TPD file `%s' is invalid according to schema `%s'", tpd_file_name, xsd_file_name);
192 return false;
193 } else {
194 ERROR("TPD validation of `%s' generated an internal error in libxml2", tpd_file_name);
195 return false;
196 }
197 }
198
199 /** Extract a boolean value from the XML, if it exists otherwise flag is unchanged
200 *
201 * @param xpathCtx XPath context object
202 * @param actcfg name of the active configuration
203 * @param option name of the value
204 * @param flag pointer to the variable to receive the value
205 */
206 void xsdbool2boolean(const XPathContext& xpathCtx, const char *actcfg,
207 const char *option, boolean* flag)
208 {
209 char *xpath = mprintf(
210 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
211 "/ProjectProperties/MakefileSettings/%s[text()='true']",
212 actcfg, option);
213 XPathObject xpathObj(run_xpath(xpathCtx, xpath));
214 Free(xpath);
215
216 if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
217 *flag = TRUE;
218 }
219 }
220
221 // data structures and functions to manage excluded folders/files
222
223 map<cstring, void> excluded_files;
224
225 boolean is_excluded_file(const cstring& path) {
226 return excluded_files.has_key(path);
227 }
228
229 vector<const char> excluded_folders;
230
231 // Unfortunately, when "docs" is excluded, we need to drop
232 // files in "docs/", "docs/pdf/", "docs/txt/", "docs/txt/old/" etc;
233 // so it's not as simple as using a map :(
234
235 /** Checks whether a file is under an excluded folder
236 *
237 * @param path (relative) path of the file
238 * @return true if file is excluded, false otherwise
239 */
240 boolean is_excluded_folder(const char *path) {
241 boolean answer = FALSE;
242 size_t pathlen = strlen(path);
243
244 for (size_t i = 0, end = excluded_folders.size(); i < end; ++i) {
245 const char *xdir = excluded_folders[i];
246 size_t xdlen = strlen(xdir);
247 if (pathlen > xdlen && path[xdlen] == '/') {
248 // we may have a winner
249 if ((answer = !strncmp(path, xdir, xdlen))) break;
250 }
251 }
252 return answer;
253 }
254
255 // How do you treat a raw info? You cook it, of course!
256 // Returns a newly allocated string.
257 char *cook(const char *raw, const map<cstring, const char>& path_vars)
258 {
259 const char *slash = strchr(raw, '/');
260 if (!slash) { // Pretend that the slash is at the end of the string.
261 slash = raw + strlen(raw);
262 }
263
264 // Assume that a path variable reference is the first (or only) component
265 // of the path: ROOT in "ROOT/etc/issue".
266 autostring prefix(mcopystrn(raw, slash - raw));
267 if (path_vars.has_key(prefix)) {
268 char *cooked = mcopystr(path_vars[prefix]);
269 bool ends_with_slash = cooked[strlen(cooked)-1] == '/';
270 if (ends_with_slash && *slash == '/') {
271 // Avoid paths with two slashes at the start; Cygwin thinks it's UNC
272 ++slash;
273 }
274 // If there was no '/' (only the path variable reference e.g "ROOT")
275 // then slash points to a null byte and the mputstr is a no-op.
276 cooked = mputstr(cooked, slash);
277 return cooked;
278 }
279
280 // If the path variable could not be substituted,
281 // return (a copy of) the original.
282 return mcopystr(raw);
283 }
284
285 void replacechar(char** content) {
286
287 std::string s= *content;
288 size_t found = 0;
289 while ((found = s.find('['))!= std::string::npos){
290 s.replace(found,1, "${");
291 }
292 while ((found = s.find(']')) != std::string::npos){
293 s.replace(found,1, "}");
294 }
295 *content = mcopystr(s.c_str());
296 }
297
298 static void clear_seen_tpd_files(map<cstring, int>& seen_tpd_files) {
299 for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
300 const cstring& key = seen_tpd_files.get_nth_key(i);
301 int *elem = seen_tpd_files.get_nth_elem(i);
302 key.destroy();
303 delete elem;
304 }
305 seen_tpd_files.clear();
306 }
307
308 static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg,
309 const char *file_list_path, int *p_argc, char ***p_argv,
310 int *p_optind, char **p_ets_name,
311 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
312 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
313 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
314 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
315 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
316 struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines,
317 boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler,
318 char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag,
319 boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
320 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
321 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
322 struct string_list* linkerlibs, struct string_list* additionalObjects, struct string_list* linkerlibsearchp, boolean Vflag, boolean Dflag,
323 char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list,
324 map<cstring, int>& seen_tpd_files);
325
326 extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
327 const char *file_list_path, int *p_argc, char ***p_argv,
328 int *p_optind, char **p_ets_name,
329 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
330 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
331 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
332 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
333 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
334 struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines,
335 boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler,
336 char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag,
337 boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
338 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
339 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
340 string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag,
341 char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list) {
342
343 map<cstring, int> seen_tpd_files;
344
345 tpd_result success = process_tpd_internal(p_tpd_name,
346 actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name,
347 p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
348 p_Rflag, p_lflag, p_mflag, p_Pflag,
349 p_Lflag, recursive, force_overwrite, gen_only_top_level,
350 output_file, abs_work_dir_p, sub_project_dirs,
351 program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes,
352 ttcn3_prep_defines, prep_includes, prep_defines,
353 p_csflag, p_quflag, p_dsflag, cxxcompiler,
354 optlevel, optflags, p_dbflag, p_drflag, p_dtflag, p_dxflag, p_djflag,
355 p_fxflag, p_doflag, p_gfflag, p_lnflag, p_isflag,
356 p_asflag, p_swflag, p_Yflag, solspeclibs, sol8speclibs,
357 linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep,
358 linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag,
359 generatorCommandOutput, target_placement_list, prefix_workdir, run_command_list, seen_tpd_files);
360
361 for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
362 const cstring& key = seen_tpd_files.get_nth_key(i);
363 int *elem = seen_tpd_files.get_nth_elem(i);
364 key.destroy();
365 delete elem;
366 }
367 seen_tpd_files.clear();
368
369 return success;
370 }
371
372 // optind is the index of the next element of argv to be processed.
373 // Return TPD_SUCESS if parsing successful, TPD_SKIPPED if the tpd was
374 // seen already, or TPD_FAILED.
375 //
376 // Note: if process_tpd() returns TPD_SUCCESS, it is expected that all strings
377 // (argv[], ets_name, other_files[], output_file) are allocated on the heap
378 // and need to be freed. On input, these strings point into argv.
379 // process_tpd() may alter these strings; new values will be on the heap.
380 // If process_tpd() preserves the content of such a string (e.g. ets_name),
381 // it must nevertheless make a copy on the heap via mcopystr().
382 static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg,
383 const char *file_list_path, int *p_argc, char ***p_argv,
384 int *p_optind, char **p_ets_name,
385 boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
386 boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
387 boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level,
388 const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs,
389 const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes,
390 struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines,
391 boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler,
392 char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag,
393 boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag,
394 boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs,
395 struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep,
396 string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag,
397 char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list,
398 map<cstring, int>& seen_tpd_files)
399 {
400 // read-only non-pointer aliases
401 //char** const& local_argv = *p_argv;
402 int const& local_argc = *p_argc;
403 int const& local_optind = *p_optind;
404 *abs_work_dir_p = NULL;
405
406 assert(local_optind >= 2 // at least '-ttpd_name' must be in the args
407 || local_optind == 0); // if called for a referenced project
408
409 assert(local_argc >= local_optind);
410
411 autostring tpd_dir(get_dir_from_path(p_tpd_name));
412 autostring abs_tpd_dir(get_absolute_dir(tpd_dir, NULL));
413
414 autostring tpd_filename(get_file_from_path(p_tpd_name));
415 autostring abs_tpd_name(compose_path_name(abs_tpd_dir, tpd_filename));
416
417 if (seen_tpd_files.has_key(abs_tpd_name)) {
418 ++*seen_tpd_files[abs_tpd_name];
419 return TPD_SKIPPED; // nothing to do
420 }
421 else {
422 if (recursive && !prefix_workdir) {
423 // check that this tpd file is not inside a directory of another tpd file
424 for (size_t i = 0; i < seen_tpd_files.size(); ++i) {
425 const cstring& other_tpd_name = seen_tpd_files.get_nth_key(i);
426 autostring other_tpd_dir(get_dir_from_path((const char*)other_tpd_name));
427 if (strcmp((const char*)abs_tpd_dir,(const char*)other_tpd_dir)==0) {
428 ERROR("TPD files `%s' and `%s' are in the same directory! Use the `-W' option.", (const char*)abs_tpd_name, (const char*)other_tpd_name);
429 return TPD_FAILED;
430 }
431 }
432 }
433 // mcopystr makes another copy for the map
434 seen_tpd_files.add(cstring(mcopystr(abs_tpd_name)), new int(1));
435 }
436
437 vector<char> base_files; // values Malloc'd but we pass them to the caller
438
439 XmlDoc doc(xmlParseFile(p_tpd_name));
440 if (doc == NULL) {
441 fprintf(stderr, "Error: unable to parse file \"%s\"\n", p_tpd_name);
442 return TPD_FAILED;
443 }
444
445 if (!Vflag) {
446 // try schema validation if tpd schema file was found
447 bool tpd_is_valid = false;
448 const char* ttcn3_dir = getenv("TTCN3_DIR");
449 if (ttcn3_dir) {
450 size_t ttcn3_dir_len = strlen(ttcn3_dir);
451 bool ends_with_slash = (ttcn3_dir_len>0) && (ttcn3_dir[ttcn3_dir_len - 1]=='/');
452 expstring_t xsd_file_name = mprintf("%s%setc/xsd/TPD.xsd", ttcn3_dir, ends_with_slash?"":"/");
453 autostring xsd_file_name_as(xsd_file_name);
454 if (get_path_status(xsd_file_name)==PS_FILE) {
455 if (validate_tpd(doc, p_tpd_name, xsd_file_name)) {
456 tpd_is_valid = true;
457 NOTIFY("TPD file `%s' validated successfully with schema file `%s'", p_tpd_name, xsd_file_name);
458 }
459 } else {
460 ERROR("Cannot find XSD for schema for validation of TPD on path `%s'", xsd_file_name);
461 }
462 } else {
463 ERROR("Environment variable TTCN3_DIR not present, cannot find XSD for schema validation of TPD");
464 }
465 if (!tpd_is_valid) {
466 return TPD_FAILED;
467 }
468 }
469
470 // Source files.
471 // Key is projectRelativePath, value is relativeURI or rawURI.
472 map<cstring, const char> files; // values Malloc'd
473 map<cstring, const char> folders; // values Malloc'd
474 // NOTE! files and folders must be local variables of process_tpd.
475 // This is because the keys (not the values) are owned by the XmlDoc.
476
477 map<cstring, const char> path_vars;
478
479 XPathContext xpathCtx(xmlXPathNewContext(doc));
480 if (xpathCtx == NULL) {
481 fprintf(stderr,"Error: unable to create new XPath context\n");
482 return TPD_FAILED;
483 }
484 // Collect path variables
485 {
486 XPathObject pathsObj(run_xpath(xpathCtx,
487 "/TITAN_Project_File_Information/PathVariables/PathVariable"));
488 xmlNodeSetPtr nodes = pathsObj->nodesetval;
489
490 const char *name = 0, *value = 0;
491 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
492 // nodes->nodeTab[i]->name === "PathVariable"
493 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
494 if (!strcmp((const char*)attr->name, "name")) {
495 name = (const char*)attr->children->content;
496 }
497 else if (!strcmp((const char*)attr->name, "value")) {
498 value = (const char*)attr->children->content;
499 }
500 else {
501 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
502 }
503 } // next attribute
504
505 if (name && value) path_vars.add(cstring(name), value);
506 else ERROR("A PathVariable must have both name and value");
507 } // next PathVariable
508 }
509
510 // Collect folders
511 {
512 XPathObject foldersObj(run_xpath(xpathCtx,
513 "/TITAN_Project_File_Information/Folders/FolderResource"));
514
515 xmlNodeSetPtr nodes = foldersObj->nodesetval;
516 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
517 // nodes->nodeTab[i]->name === "FolderResource"
518 const char *uri = 0, *path = 0, *raw = 0;
519
520 // projectRelativePath is the path as it appears in Project Explorer (illusion)
521 // relativeURI is the actual location, relative to the project root (reality)
522 // rawURI is present if the relative path can not be calculated
523 //
524 // Theoretically these attributes could be in any order, loop over them
525 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
526 if (!strcmp((const char*)attr->name, "projectRelativePath")) {
527 path = (const char*)attr->children->content;
528 }
529 else if (!strcmp((const char*)attr->name, "relativeURI")) {
530 uri = (const char*)attr->children->content;
531 }
532 else if (!strcmp((const char*)attr->name, "rawURI")) {
533 raw = (const char*)attr->children->content;
534 }
535 else {
536 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
537 }
538 } // next attribute
539
540 if (path == NULL) {
541 ERROR("A FolderResource must have a projectRelativePath");
542 continue;
543 }
544
545 if (uri == NULL && raw == NULL) {
546 ERROR("A FolderResource must have either relativeURI or rawURI");
547 continue;
548 }
549 // relativeURI wins over rawURI
550 folders.add(cstring(path), uri ? mcopystr(uri) : cook(raw, path_vars));
551 // TODO uri: cut "file:", complain on anything else
552 } // next FolderResource
553 }
554
555 if (actcfg == NULL)
556 {
557 // Find out the active config
558 XPathObject activeConfig(run_xpath(xpathCtx,
559 "/TITAN_Project_File_Information/ActiveConfiguration/text()"));
560 if (activeConfig->nodesetval && activeConfig->nodesetval->nodeNr == 1) {
561 // there is one node
562 actcfg = (const char*)activeConfig->nodesetval->nodeTab[0]->content;
563 }
564 }
565
566 if (actcfg == NULL) {
567 ERROR("Can not find the active build configuration.");
568 for (size_t i = 0; i < folders.size(); ++i) {
569 Free(const_cast<char*>(folders.get_nth_elem(i)));
570 }
571 folders.clear();
572 return TPD_FAILED;
573 }
574
575 { // check if the active configuration exists
576 expstring_t xpathActCfg= mprintf(
577 "/TITAN_Project_File_Information/Configurations/"
578 "Configuration[@name='%s']/text()", actcfg);
579 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfg));
580 Free(xpathActCfg);
581
582 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
583 if (nodes == NULL) {
584 ERROR("The active build configuration named '%s' does not exist",
585 actcfg);
586 for (size_t i = 0; i < folders.size(); ++i) {
587 Free(const_cast<char*>(folders.get_nth_elem(i)));
588 }
589 folders.clear();
590 return TPD_FAILED;
591 }
592 }
593
594 /////////////////////////////////////////////////////////////////////////////
595 // working directory stuff
596 autostring workdir;
597 {
598 const char* workdirFromTpd = "bin"; // default value
599 char *workdirXpath = mprintf(
600 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
601 "/ProjectProperties/LocalBuildSettings/workingDirectory/text()",
602 actcfg);
603 XPathObject workdirObj(run_xpath(xpathCtx, workdirXpath));
604 Free(workdirXpath);
605 if (workdirObj->nodesetval && workdirObj->nodesetval->nodeNr > 0) {
606 workdirFromTpd = (const char*)workdirObj->nodesetval->nodeTab[0]->content;
607 }
608 if (prefix_workdir) { // the working directory is: prjNameStr + "_" + workdirFromTpd
609 const char* prjNameStr = "unnamedproject";
610 XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
611 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
612 prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
613 }
614 workdir = mprintf("%s_%s", prjNameStr, workdirFromTpd);
615 } else {
616 workdir = mcopystr(workdirFromTpd);
617 }
618 }
619 if (!folders.has_key(workdir)) {
620 // Maybe the tpd was saved with the option "No info about work dir"
621 folders.add(workdir, mcopystr(workdir)); // fake it
622 }
623 const char *real_workdir = folders[workdir]; // This is relative to the location of the tpd file
624 excluded_folders.add(real_workdir); // excluded by convention
625
626 autostring abs_workdir;
627 // If -D flag was specified then we ignore the workdir
628 // in the TPD (the current dir is considered the work dir).
629 if (!Dflag) {
630 bool hasWorkDir = false;
631 // if the working directory does not exist create it
632 autostring saved_work_dir(get_working_dir());
633 if (set_working_dir(abs_tpd_dir)) {
634 ERROR("Could not change to project directory `%s'", (const char*)abs_tpd_dir);
635 } else {
636 switch (get_path_status(real_workdir)) {
637 case PS_FILE:
638 ERROR("Cannot create working directory `%s' in project directory `%s' because a file with the same name exists", (const char*)abs_tpd_dir, real_workdir);
639 break;
640 case PS_DIRECTORY:
641 // already exists
642 hasWorkDir = true;
643 break;
644 default:
645 if (recursive || local_argc != 0) { // we only want to create workdir if necessary
646 printf("Working directory `%s' in project `%s' does not exist, trying to create it...\n", real_workdir, (const char*)abs_tpd_dir);
647 int rv = mkdir(real_workdir, 0755);
648 if (rv) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno));
649 else printf("Working directory created\n");
650 hasWorkDir = true;
651 }
652 }
653 }
654
655 if (local_argc==0) { // if not top level
656 set_working_dir(saved_work_dir); // restore working directory
657 } else { // if top level
658 set_working_dir(real_workdir); // go into the working dir
659 }
660 if (hasWorkDir) { //we created working directory, or its already been created (from a parent makefilegen process maybe)
661 *abs_work_dir_p = get_absolute_dir(real_workdir, abs_tpd_dir);
662 abs_workdir = (mcopystr(*abs_work_dir_p));
663 }
664 }
665 /////////////////////////////////////////////////////////////////////////////
666
667 // Gather the excluded folders in the active config
668 {
669 expstring_t xpathActCfgPaths = mprintf(
670 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
671 "/FolderProperties/FolderResource/FolderProperties/ExcludeFromBuild[text()='true']"
672 // This was the selection criterium, we need to go up and down for the actual information
673 "/parent::*/parent::*/FolderPath/text()",
674 actcfg);
675 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
676 Free(xpathActCfgPaths);
677
678 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
679 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
680
681 excluded_folders.add((const char*)nodes->nodeTab[i]->content);
682 }
683 }
684
685 // Gather individual excluded files in the active config
686 {
687 expstring_t xpathActCfgPaths = mprintf(
688 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
689 "/FileProperties/FileResource/FileProperties/ExcludeFromBuild[text()='true']"
690 "/parent::*/parent::*/FilePath/text()",
691 actcfg);
692 XPathObject theConfigEx(run_xpath(xpathCtx, xpathActCfgPaths));
693 Free(xpathActCfgPaths);
694
695 xmlNodeSetPtr nodes = theConfigEx->nodesetval;
696 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
697 xmlNodePtr curnode = nodes->nodeTab[i];
698
699 cstring aa((const char*)curnode->content);
700 excluded_files.add(aa, 0);
701 }
702 }
703
704 // Collect files; filter out excluded ones
705 {
706 XPathObject filesObj(run_xpath(xpathCtx,
707 "TITAN_Project_File_Information/Files/FileResource"));
708
709 xmlNodeSetPtr nodes = filesObj->nodesetval;
710 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
711 // nodes->nodeTab[i]->name === "FileResource"
712 const char *uri = 0, *path = 0, *raw = 0;
713
714 // projectRelativePath is the path as it appears in Project Explorer (illusion)
715 // relativeURI is the actual location, relative to the project root (reality)
716 // rawURI is present if the relative path can not be calculated
717 //
718 // Theoretically these attributes could be in any order, loop over them
719 for (xmlAttrPtr attr = nodes->nodeTab[i]->properties; attr; attr = attr->next) {
720 if (!strcmp((const char*)attr->name, "projectRelativePath")) {
721 path = (const char*)attr->children->content;
722 }
723 else if (!strcmp((const char*)attr->name, "relativeURI")) {
724 uri = (const char*)attr->children->content;
725 }
726 else if (!strcmp((const char*)attr->name, "rawURI")) {
727 raw = (const char*)attr->children->content;
728 }
729 else {
730 WARNING("Unknown attribute %s", (const char*)nodes->nodeTab[i]->name);
731 }
732 } // next attribute
733
734 if (path == NULL) {
735 ERROR("A FileResource must have a projectRelativePath");
736 continue;
737 }
738
739 if (uri == NULL && raw == NULL) {
740 ERROR("A FileResource must have either relativeURI or rawURI");
741 continue;
742 }
743
744 cstring cpath(path);
745 if (!is_excluded_file(cpath) && !is_excluded_folder(path)) {
746 // relativeURI wins over rawURI
747 char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars);
748
749 if (files.has_key(cpath)) {
750 ERROR("A FileResource %s must be unique!", (const char*)cpath);
751 } else {
752 files.add(cpath, ruri); // relativeURI to the TPD location
753 { // set the *preprocess value if .ttcnpp file was found
754 const size_t ttcnpp_extension_len = 7; // ".ttcnpp"
755 const size_t ruri_len = strlen(ruri);
756 if ( ruri_len>ttcnpp_extension_len && strcmp(ruri+(ruri_len-ttcnpp_extension_len),".ttcnpp")==0 ) {
757 *preprocess = TRUE;
758 }
759 }
760 }
761 }
762 } // next FileResource
763 }
764
765 // Check options
766 xsdbool2boolean(xpathCtx, actcfg, "useAbsolutePath", p_aflag);
767 xsdbool2boolean(xpathCtx, actcfg, "GNUMake", p_gflag);
768 xsdbool2boolean(xpathCtx, actcfg, "dynamicLinking", p_lflag);
769 xsdbool2boolean(xpathCtx, actcfg, "functiontestRuntime", p_Rflag);
770 xsdbool2boolean(xpathCtx, actcfg, "singleMode", p_sflag);
771 xsdbool2boolean(xpathCtx, actcfg, "codeSplitting", p_csflag);
772 xsdbool2boolean(xpathCtx, actcfg, "quietly", p_quflag);
773 xsdbool2boolean(xpathCtx, actcfg, "disableSubtypeChecking", p_dsflag);
774 xsdbool2boolean(xpathCtx, actcfg, "disableBER", p_dbflag);
775 xsdbool2boolean(xpathCtx, actcfg, "disableRAW", p_drflag);
776 xsdbool2boolean(xpathCtx, actcfg, "disableTEXT", p_dtflag);
777 xsdbool2boolean(xpathCtx, actcfg, "disableXER", p_dxflag);
778 xsdbool2boolean(xpathCtx, actcfg, "disableJSON", p_djflag);
779 xsdbool2boolean(xpathCtx, actcfg, "forceXERinASN.1", p_fxflag);
780 xsdbool2boolean(xpathCtx, actcfg, "defaultasOmit", p_doflag);
781 xsdbool2boolean(xpathCtx, actcfg, "gccMessageFormat", p_gfflag);
782 xsdbool2boolean(xpathCtx, actcfg, "lineNumbersOnlyInMessages", p_lnflag);
783 xsdbool2boolean(xpathCtx, actcfg, "includeSourceInfo", p_isflag);
784 xsdbool2boolean(xpathCtx, actcfg, "addSourceLineInfo", p_asflag);
785 xsdbool2boolean(xpathCtx, actcfg, "suppressWarnings", p_swflag);
786 xsdbool2boolean(xpathCtx, actcfg, "outParamBoundness", p_Yflag);
787
788 // Extract the "incremental dependencies" option
789 {
790 boolean incremental_deps = TRUE;
791 xsdbool2boolean(xpathCtx, actcfg, "incrementalDependencyRefresh", &incremental_deps);
792
793 // For makefilegen, "Use GNU make" implies incremental deps by default,
794 // unless explicitly disabled by "use makedepend" (a.k.a. mflag).
795 // For Eclipse, incremental deps must be explicitly specified,
796 // even if GNU make is being used.
797
798 if (incremental_deps) {
799 if( !(*p_gflag) ) {
800 WARNING("Incremental dependency ordered but it requires gnu make");
801 }
802 }
803 else {
804 if (*p_gflag) {
805 // GNU make but no incremental deps
806 *p_mflag = true;
807 }
808 }
809 }
810
811 // Extract the default target option
812 // if it is not defined as a command line argument
813 if (!(*p_Lflag)) {
814 char *defTargetXpath = mprintf(
815 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
816 "/ProjectProperties/MakefileSettings/defaultTarget/text()",
817 actcfg);
818 XPathObject defTargetObj(run_xpath(xpathCtx, defTargetXpath));
819 Free(defTargetXpath);
820 if (defTargetObj->nodesetval && defTargetObj->nodesetval->nodeNr > 0) {
821 const char* content = (const char*)defTargetObj->nodesetval->nodeTab[0]->content;
822 if (!strcmp(content, "library")) {
823 *p_Lflag = true;
824 } else if (!strcmp(content, "executable")) {
825 *p_Lflag = false;
826 } else {
827 ERROR("Unknown default target: '%s'."
828 " The available targets are: 'executable', 'library'", content);
829 }
830 }
831 }
832
833 // Executable name (don't care unless top-level invocation)
834 if (local_argc != 0)
835 {
836 char *exeXpath = mprintf(
837 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
838 "/ProjectProperties/MakefileSettings/targetExecutable/text()",
839 actcfg);
840 XPathObject exeObj(run_xpath(xpathCtx, exeXpath));
841 Free(exeXpath);
842 if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) {
843 const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content;
844 autostring target_exe_dir(get_dir_from_path(target_executable));
845 autostring target_exe_file(get_file_from_path(target_executable));
846 if (target_exe_dir!=NULL) { // if it's not only a file name
847 if (get_path_status(target_exe_dir)==PS_NONEXISTENT) {
848 if (strcmp(real_workdir,target_exe_dir)!=0) {
849 WARNING("Provided targetExecutable directory `%s' does not exist, only file name `%s' will be used", (const char*)target_exe_dir, (const char*)target_exe_file);
850 }
851 target_executable = target_exe_file;
852 }
853 }
854 if (!*p_ets_name) { // Command line will win
855 *p_ets_name = mcopystr(target_executable);
856 }
857 }
858 }
859
860 // create an xml element for the currently processed project
861 if (prj_graph_fp) {
862 const char* prjNameStr = "???";
863 XPathObject prjName(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ProjectName/text()"));
864 if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) {
865 prjNameStr = (const char*)prjName->nodesetval->nodeTab[0]->content;
866 }
867 autostring tpd_rel_dir(get_relative_dir(tpd_dir, NULL));
868 autostring tpd_rel_path(compose_path_name(tpd_rel_dir, (const char*)tpd_filename));
869 fprintf(prj_graph_fp, "<project name=\"%s\" uri=\"%s\">\n", prjNameStr, (const char*)tpd_rel_path);
870 XPathObject subprojects(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::name"));
871 xmlNodeSetPtr nodes = subprojects->nodesetval;
872 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
873 const char* refd_name = "???";
874 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
875 refd_name = (const char*)nodes->nodeTab[i]->children->content;
876 }
877 fprintf(prj_graph_fp, "<reference name=\"%s\"/>\n", refd_name);
878 }
879 fprintf(prj_graph_fp, "</project>\n");
880 }
881
882 // Tpd part of the MakefileSettings
883 {
884 //TTCN3preprocessorIncludes
885 char *preincludeXpath = mprintf(
886 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
887 "/ProjectProperties/MakefileSettings/TTCN3preprocessorIncludes/listItem/text()",
888 actcfg);
889 XPathObject preincludeObj(run_xpath(xpathCtx, preincludeXpath));
890 Free(preincludeXpath);
891
892 xmlNodeSetPtr nodes = preincludeObj->nodesetval;
893
894 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
895 char* content = (char*)preincludeObj->nodesetval->nodeTab[i]->content;
896
897 // add includes to the end of list
898 if (ttcn3_prep_includes) {
899 // go to last element
900 struct string_list* last_elem = ttcn3_prep_includes;
901 while (last_elem->next) last_elem = last_elem->next;
902 // add string to last element if empty or create new last element and add it to that
903 if (last_elem->str) {
904 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
905 last_elem = last_elem->next;
906 last_elem->next = NULL;
907 }
908 replacechar(&content);
909 last_elem->str = content;
910 }
911 }
912 }
913 {
914 //TTCN3preprocessorDefines
915 char *ttcn3predefinesXpath = mprintf(
916 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
917 "/ProjectProperties/MakefileSettings/TTCN3preprocessorDefines/listItem/text()",
918 actcfg);
919 XPathObject ttcn3predefinesObj(run_xpath(xpathCtx, ttcn3predefinesXpath));
920 Free(ttcn3predefinesXpath);
921
922 xmlNodeSetPtr nodes = ttcn3predefinesObj->nodesetval;
923
924 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
925 const char* content = (const char*)ttcn3predefinesObj->nodesetval->nodeTab[i]->content;
926
927 // add includes to the end of list
928 if (ttcn3_prep_defines) {
929 // go to last element
930 struct string_list* last_elem = ttcn3_prep_defines;
931 while (last_elem->next) last_elem = last_elem->next;
932 // add string to last element if empty or create new last element and add it to that
933 if (last_elem->str) {
934 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
935 last_elem = last_elem->next;
936 last_elem->next = NULL;
937 }
938 last_elem->str = mcopystr(content);
939 }
940 }
941 }
942 {
943 //preprocessorIncludes
944 char *preincludesXpath = mprintf(
945 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
946 "/ProjectProperties/MakefileSettings/preprocessorIncludes/listItem/text()",
947 actcfg);
948 XPathObject preincludesObj(run_xpath(xpathCtx, preincludesXpath));
949 Free(preincludesXpath);
950
951 xmlNodeSetPtr nodes = preincludesObj->nodesetval;
952
953 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
954 char* content = (char*)preincludesObj->nodesetval->nodeTab[i]->content;
955
956 // add includes to the end of list
957 if (prep_includes) {
958 // go to last element
959 struct string_list* last_elem = prep_includes;
960 while (last_elem->next) last_elem = last_elem->next;
961 // add string to last element if empty or create new last element and add it to that
962 if (last_elem->str) {
963 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
964 last_elem = last_elem->next;
965 last_elem->next = NULL;
966 }
967 replacechar(&content);
968 last_elem->str = content;
969 }
970 }
971 }
972 {
973 //preprocessorDefines
974 char *predefinesXpath = mprintf(
975 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
976 "/ProjectProperties/MakefileSettings/preprocessorDefines/listItem/text()",
977 actcfg);
978 XPathObject predefinesObj(run_xpath(xpathCtx, predefinesXpath));
979 Free(predefinesXpath);
980
981 xmlNodeSetPtr nodes = predefinesObj->nodesetval;
982
983 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
984 const char* content = (const char*)predefinesObj->nodesetval->nodeTab[i]->content;
985
986 // add includes to the end of list
987 if (prep_defines) {
988 // go to last element
989 struct string_list* last_elem = prep_defines;
990 while (last_elem->next) last_elem = last_elem->next;
991 // add string to last element if empty or create new last element and add it to that
992 if (last_elem->str) {
993 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
994 last_elem = last_elem->next;
995 last_elem->next = NULL;
996 }
997 last_elem->str = mcopystr(content);
998 }
999 }
1000 }
1001 {
1002 char *cxxCompilerXpath = mprintf(
1003 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1004 "/ProjectProperties/MakefileSettings/CxxCompiler/text()",
1005 actcfg);
1006 XPathObject cxxCompilerObj(run_xpath(xpathCtx, cxxCompilerXpath));
1007 Free(cxxCompilerXpath);
1008 xmlNodeSetPtr nodes = cxxCompilerObj->nodesetval;
1009 if (nodes) {
1010 *cxxcompiler = mcopystr((const char*)cxxCompilerObj->nodesetval->nodeTab[0]->content);
1011 }
1012 }
1013 {
1014 char *optLevelXpath = mprintf(
1015 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1016 "/ProjectProperties/MakefileSettings/optimizationLevel/text()",
1017 actcfg);
1018 XPathObject optLevelObj(run_xpath(xpathCtx, optLevelXpath));
1019 Free(optLevelXpath);
1020 xmlNodeSetPtr nodes = optLevelObj->nodesetval;
1021 if (nodes) {
1022 *optlevel = mcopystr((const char*)optLevelObj->nodesetval->nodeTab[0]->content);
1023 }
1024 }
1025 {
1026 char *optFlagsXpath = mprintf(
1027 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1028 "/ProjectProperties/MakefileSettings/otherOptimizationFlags/text()",
1029 actcfg);
1030 XPathObject optFlagsObj(run_xpath(xpathCtx, optFlagsXpath));
1031 Free(optFlagsXpath);
1032 xmlNodeSetPtr nodes = optFlagsObj->nodesetval;
1033 if (nodes) {
1034 *optflags = mcopystr((const char*)optFlagsObj->nodesetval->nodeTab[0]->content);
1035 }
1036 }
1037 {
1038 //SolarisSpecificLibraries
1039 char *solspeclibXpath = mprintf(
1040 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1041 "/ProjectProperties/MakefileSettings/SolarisSpecificLibraries/listItem/text()",
1042 actcfg);
1043 XPathObject solspeclibObj(run_xpath(xpathCtx, solspeclibXpath));
1044 Free(solspeclibXpath);
1045
1046 xmlNodeSetPtr nodes = solspeclibObj->nodesetval;
1047
1048 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1049 char* content = (char*)solspeclibObj->nodesetval->nodeTab[i]->content;
1050
1051 // add includes to the end of list
1052 if (solspeclibs) {
1053 // go to last element
1054 struct string_list* last_elem =solspeclibs;
1055 while (last_elem->next) last_elem = last_elem->next;
1056 // add string to last element if empty or create new last element and add it to that
1057 if (last_elem->str) {
1058 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1059 last_elem = last_elem->next;
1060 last_elem->next = NULL;
1061 }
1062 replacechar(&content);
1063 last_elem->str = content;
1064 }
1065 }
1066 }
1067 {
1068 //Solaris8SpecificLibraries
1069 char *sol8speclibXpath = mprintf(
1070 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1071 "/ProjectProperties/MakefileSettings/Solaris8SpecificLibraries/listItem/text()",
1072 actcfg);
1073 XPathObject sol8speclibObj(run_xpath(xpathCtx, sol8speclibXpath));
1074 Free(sol8speclibXpath);
1075
1076 xmlNodeSetPtr nodes = sol8speclibObj->nodesetval;
1077
1078 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1079 char* content = (char*)sol8speclibObj->nodesetval->nodeTab[i]->content;
1080
1081 // add includes to the end of list
1082 if (sol8speclibs) {
1083 // go to last element
1084 struct string_list* last_elem = sol8speclibs;
1085 while (last_elem->next) last_elem = last_elem->next;
1086 // add string to last element if empty or create new last element and add it to that
1087 if (last_elem->str) {
1088 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1089 last_elem = last_elem->next;
1090 last_elem->next = NULL;
1091 }
1092 replacechar(&content);
1093 last_elem->str = content;
1094 }
1095 }
1096 }
1097 {
1098 //LinuxSpecificLibraries
1099 char *linuxspeclibXpath = mprintf(
1100 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1101 "/ProjectProperties/MakefileSettings/LinuxSpecificLibraries/listItem/text()",
1102 actcfg);
1103 XPathObject linuxspeclibObj(run_xpath(xpathCtx, linuxspeclibXpath));
1104 Free(linuxspeclibXpath);
1105
1106 xmlNodeSetPtr nodes = linuxspeclibObj->nodesetval;
1107
1108 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1109 char* content = (char*)linuxspeclibObj->nodesetval->nodeTab[i]->content;
1110
1111 // add includes to the end of list
1112 if (linuxspeclibs) {
1113 // go to last element
1114 struct string_list* last_elem = linuxspeclibs;
1115 while (last_elem->next) last_elem = last_elem->next;
1116 // add string to last element if empty or create new last element and add it to that
1117 if (last_elem->str) {
1118 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1119 last_elem = last_elem->next;
1120 last_elem->next = NULL;
1121 }
1122 replacechar(&content);
1123 last_elem->str = content;
1124 }
1125 }
1126 }
1127 {
1128 //FreeBSDSpecificLibraries
1129 char *freebsdspeclibXpath = mprintf(
1130 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1131 "/ProjectProperties/MakefileSettings/FreeBSDSpecificLibraries/listItem/text()",
1132 actcfg);
1133 XPathObject freebsdspeclibObj(run_xpath(xpathCtx, freebsdspeclibXpath));
1134 Free(freebsdspeclibXpath);
1135
1136 xmlNodeSetPtr nodes = freebsdspeclibObj->nodesetval;
1137
1138 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1139 char* content = (char*)freebsdspeclibObj->nodesetval->nodeTab[i]->content;
1140
1141 // add includes to the end of list
1142 if (freebsdspeclibs) {
1143 // go to last element
1144 struct string_list* last_elem = freebsdspeclibs;
1145 while (last_elem->next) last_elem = last_elem->next;
1146 // add string to last element if empty or create new last element and add it to that
1147 if (last_elem->str) {
1148 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1149 last_elem = last_elem->next;
1150 last_elem->next = NULL;
1151 }
1152 replacechar(&content);
1153 last_elem->str = content;
1154 }
1155 }
1156 }
1157 {
1158 //Win32SpecificLibraries
1159 char *win32speclibXpath = mprintf(
1160 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1161 "/ProjectProperties/MakefileSettings/Win32SpecificLibraries/listItem/text()",
1162 actcfg);
1163 XPathObject win32speclibObj(run_xpath(xpathCtx, win32speclibXpath));
1164 Free(win32speclibXpath);
1165
1166 xmlNodeSetPtr nodes = win32speclibObj->nodesetval;
1167
1168 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1169 char* content = (char*)win32speclibObj->nodesetval->nodeTab[i]->content;
1170
1171 // add includes to the end of list
1172 if (win32speclibs) {
1173 // go to last element
1174 struct string_list* last_elem = win32speclibs;
1175 while (last_elem->next) last_elem = last_elem->next;
1176 // add string to last element if empty or create new last element and add it to that
1177 if (last_elem->str) {
1178 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1179 last_elem = last_elem->next;
1180 last_elem->next = NULL;
1181 }
1182 replacechar(&content);
1183 last_elem->str = content;
1184 }
1185
1186 }
1187 }
1188 {
1189 //TTCN3preprocessor
1190 char *ttcn3preproc = mprintf(
1191 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1192 "/ProjectProperties/MakefileSettings/TTCN3preprocessor/text()",
1193 actcfg);
1194 XPathObject ttcn3preprocObj(run_xpath(xpathCtx, ttcn3preproc));
1195 Free(ttcn3preproc);
1196 xmlNodeSetPtr nodes = ttcn3preprocObj->nodesetval;
1197 if (nodes) {
1198 *ttcn3prep = mcopystr((const char*)ttcn3preprocObj->nodesetval->nodeTab[0]->content);
1199 }
1200 }
1201 {
1202 // additionalObjects
1203 char *additionalObjectsXpath = mprintf(
1204 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1205 "/ProjectProperties/MakefileSettings/additionalObjects/listItem/text()",
1206 actcfg);
1207 XPathObject additionalObjectsObj(run_xpath(xpathCtx, additionalObjectsXpath));
1208 Free(additionalObjectsXpath);
1209
1210 xmlNodeSetPtr nodes = additionalObjectsObj->nodesetval;
1211
1212 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1213 char* content = (char*)additionalObjectsObj->nodesetval->nodeTab[i]->content;
1214
1215 // add to the end of list
1216 if (additionalObjects) {
1217 // go to last element
1218 struct string_list* last_elem = additionalObjects;
1219 while (last_elem->next) last_elem = last_elem->next;
1220 // add string to last element if empty or create new last element and add it to that
1221 if (last_elem->str) {
1222 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1223 last_elem = last_elem->next;
1224 last_elem->next = NULL;
1225 }
1226 replacechar(&content);
1227 last_elem->str = content;
1228 }
1229 }
1230 }
1231 {
1232 //linkerLibraries
1233 char *linkerlibsXpath = mprintf(
1234 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1235 "/ProjectProperties/MakefileSettings/linkerLibraries/listItem/text()",
1236 actcfg);
1237 XPathObject linkerlibsObj(run_xpath(xpathCtx, linkerlibsXpath));
1238 Free(linkerlibsXpath);
1239
1240 xmlNodeSetPtr nodes = linkerlibsObj->nodesetval;
1241
1242 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1243 char* content = (char*)linkerlibsObj->nodesetval->nodeTab[i]->content;
1244
1245 // add includes to the end of list
1246 if (linkerlibs) {
1247 // go to last element
1248 struct string_list* last_elem = linkerlibs;
1249 while (last_elem->next) last_elem = last_elem->next;
1250 // add string to last element if empty or create new last element and add it to that
1251 if (last_elem->str) {
1252 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1253 last_elem = last_elem->next;
1254 last_elem->next = NULL;
1255 }
1256 replacechar(&content);
1257 last_elem->str = content;
1258 }
1259 }
1260 }
1261 {
1262 //linkerLibrarySearchPath
1263 char *linkerlibsearchXpath = mprintf(
1264 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1265 "/ProjectProperties/MakefileSettings/linkerLibrarySearchPath/listItem/text()",
1266 actcfg);
1267 XPathObject linkerlibsearchObj(run_xpath(xpathCtx, linkerlibsearchXpath));
1268 Free(linkerlibsearchXpath);
1269
1270 xmlNodeSetPtr nodes = linkerlibsearchObj->nodesetval;
1271
1272 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1273 char* content = (char*)linkerlibsearchObj->nodesetval->nodeTab[i]->content;
1274
1275 // add includes to the end of list
1276 if (linkerlibsearchp) {
1277 // go to last element
1278 struct string_list* last_elem = linkerlibsearchp;
1279 while (last_elem->next) last_elem = last_elem->next;
1280 // add string to last element if empty or create new last element and add it to that
1281 if (last_elem->str) {
1282 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1283 last_elem = last_elem->next;
1284 last_elem->next = NULL;
1285 }
1286 replacechar(&content);
1287 last_elem->str = content;
1288 }
1289 }
1290 }
1291
1292 if (generatorCommandOutput && local_argc != 0) { // only in case of top-level invocation
1293 char* generatorCommandXpath = mprintf(
1294 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1295 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/GeneratorCommand/text()",
1296 actcfg);
1297 XPathObject generatorCommandObj(run_xpath(xpathCtx, generatorCommandXpath));
1298 Free(generatorCommandXpath);
1299 autostring generatorCommand;
1300 if (generatorCommandObj->nodesetval && generatorCommandObj->nodesetval->nodeNr > 0) {
1301 generatorCommand = mcopystr((const char*)generatorCommandObj->nodesetval->nodeTab[0]->content);
1302 // run the command and capture the output
1303 printf("Executing generator command `%s' specified in `%s'...\n", (const char*)generatorCommand, (const char*)abs_tpd_name);
1304 FILE* gc_fp = popen(generatorCommand, "r");
1305 if (!gc_fp) {
1306 ERROR("Could not execute command `%s'", (const char*)generatorCommand);
1307 } else {
1308 char buff[1024];
1309 while (fgets(buff, sizeof(buff), gc_fp)!=NULL) {
1310 *generatorCommandOutput = mputstr(*generatorCommandOutput, buff);
1311 }
1312 pclose(gc_fp);
1313 }
1314 }
1315 }
1316
1317 if (target_placement_list && local_argc != 0) { // only in case of top-level invocation
1318 char* targetPlacementXpath = mprintf(
1319 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1320 "/ProjectProperties/MakefileSettings/ProjectSpecificRulesGenerator/Targets/Target/attribute::*",
1321 actcfg);
1322 XPathObject targetPlacementObj(run_xpath(xpathCtx, targetPlacementXpath));
1323 Free(targetPlacementXpath);
1324 xmlNodeSetPtr nodes = targetPlacementObj->nodesetval;
1325 const char* targetName = NULL;
1326 const char* targetPlacement = NULL;
1327 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1328 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1329 targetName = (const char*)nodes->nodeTab[i]->children->content;
1330 }
1331 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"placement")) {
1332 targetPlacement = (const char*)nodes->nodeTab[i]->children->content;
1333 }
1334 if (targetName && targetPlacement) { // collected both
1335 if (target_placement_list) {
1336 // go to last element
1337 struct string2_list* last_elem = target_placement_list;
1338 while (last_elem->next) last_elem = last_elem->next;
1339 // add strings to last element if empty or create new last element and add it to that
1340 if (last_elem->str1) {
1341 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1342 last_elem = last_elem->next;
1343 last_elem->next = NULL;
1344 }
1345 last_elem->str1 = mcopystr(targetName);
1346 last_elem->str2 = mcopystr(targetPlacement);
1347 }
1348 targetName = targetPlacement = NULL; // forget both
1349 }
1350 }
1351 }
1352
1353 // Referenced projects
1354 {
1355 XPathObject subprojects(run_xpath(xpathCtx,
1356 "/TITAN_Project_File_Information/ReferencedProjects/ReferencedProject/attribute::*"));
1357 xmlNodeSetPtr nodes = subprojects->nodesetval;
1358 const char *name = NULL, *projectLocationURI = NULL;
1359 if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) {
1360 // FIXME: this assumes every ReferencedProject has name and URI.
1361 // This is not necessarily so if the referenced project was closed
1362 // when the project was exported to TPD.
1363 // Luckily, the name from the closed project will be overwritten
1364 // by the name from the next ReferencedProject. However, if some pervert
1365 // changes the next ReferencedProject to have the projectLocationURI
1366 // as the first attribute, it will be joined to the name
1367 // of the previous, closed, ReferencedProject.
1368 if (!strcmp((const char*)nodes->nodeTab[i]->name, "name")) {
1369 name = (const char*)nodes->nodeTab[i]->children->content;
1370 }
1371 else if (!strcmp((const char*)nodes->nodeTab[i]->name,"projectLocationURI")) {
1372 projectLocationURI = (const char*)nodes->nodeTab[i]->children->content;
1373 }
1374
1375 if (name && projectLocationURI) { // collected both
1376 // see if there is a specified configuration for the project
1377 const char *my_actcfg = NULL;
1378 autostring req_xpath(mprintf(
1379 "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']"
1380 "/ProjectProperties/ConfigurationRequirements/configurationRequirement"
1381 "/projectName[text()='%s']"
1382 // Up to this point, we selected the projectName node which contains
1383 // the name of the subproject. But we want its sibling.
1384 // So we go up one and down the other path.
1385 "/parent::*/rerquiredConfiguration/text()",
1386 //Yes, it's rerquiredConfiguration; the Designer misspells it :(
1387 actcfg, name));
1388 XPathObject reqcfgObj(run_xpath(xpathCtx, req_xpath));
1389 if (reqcfgObj->nodesetval && reqcfgObj->nodesetval->nodeNr == 1) {
1390 my_actcfg = (const char*)reqcfgObj->nodesetval->nodeTab[0]->content;
1391 }
1392
1393 int my_argc = 0;
1394 char *my_args[] = { NULL };
1395 char **my_argv = my_args + 0;
1396 int my_optind = 0;
1397 boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down
1398 my_Rflag = *p_Rflag, my_Pflag = *p_Pflag,
1399 my_sflag = 0, my_Lflag = 0, my_lflag = 0, my_mflag = 0, my_csflag = 0,
1400 my_quflag = 0, my_dsflag = 0, my_dbflag = 0, my_drflag = 0,
1401 my_dtflag = 0, my_dxflag = 0, my_djflag = 0, my_fxflag = 0, my_doflag = 0,
1402 my_gfflag = 0, my_lnflag = 0, my_isflag = 0, my_asflag = 0,
1403 my_swflag = 0, my_Yflag = 0;
1404
1405 char *my_ets = NULL;
1406
1407 autostring abs_projectLocationURI(
1408 compose_path_name(abs_tpd_dir, projectLocationURI));
1409
1410 char* sub_proj_abs_work_dir = NULL;
1411 tpd_result success = process_tpd_internal((const char*)abs_projectLocationURI,
1412 my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets,
1413 &my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag,
1414 &my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir,
1415 sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, prep_includes, prep_defines, &my_csflag,
1416 &my_quflag, &my_dsflag, cxxcompiler, optlevel, optflags, &my_dbflag, &my_drflag,
1417 &my_dtflag, &my_dxflag, &my_djflag, &my_fxflag, &my_doflag,
1418 &my_gfflag, &my_lnflag, &my_isflag, &my_asflag, &my_swflag, &my_Yflag, solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs,
1419 ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files);
1420 autostring sub_proj_abs_work_dir_as(sub_proj_abs_work_dir); // ?!
1421
1422 if (success == TPD_SUCCESS) {
1423
1424 if (recursive) { // call ttcn3_makefilegen on referenced project's tpd file
1425 // -r is not needed any more because top level process traverses all projects recursively
1426 expstring_t command = mprintf("%s -cVD", program_name);
1427 if (force_overwrite) command = mputc(command, 'f');
1428 if (prefix_workdir) command = mputc(command, 'W');
1429 if (*p_gflag) command = mputc(command, 'g');
1430 if (*p_sflag) command = mputc(command, 's');
1431 if (*p_aflag) command = mputc(command, 'a');
1432 if (*p_Rflag) command = mputc(command, 'R');
1433 if (*p_lflag) command = mputc(command, 'l');
1434 if (*p_mflag) command = mputc(command, 'm');
1435 command = mputstr(command, " -t ");
1436 command = mputstr(command, (const char*)abs_projectLocationURI);
1437 if (my_actcfg) {
1438 command = mputstr(command, " -b ");
1439 command = mputstr(command, my_actcfg);
1440 }
1441
1442 autostring sub_tpd_dir(get_dir_from_path((const char*)abs_projectLocationURI));
1443 const char * sub_proj_effective_work_dir = sub_proj_abs_work_dir ? sub_proj_abs_work_dir : (const char*)sub_tpd_dir;
1444 if (!gen_only_top_level) {
1445 if (run_command_list) {
1446 // go to last element
1447 struct string2_list* last_elem = run_command_list;
1448 while (last_elem->next) last_elem = last_elem->next;
1449 // add strings to last element if empty or create new last element and add it to that
1450 if (last_elem->str1 || last_elem->str2) {
1451 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1452 last_elem = last_elem->next;
1453 last_elem->next = NULL;
1454 }
1455 last_elem->str1 = mcopystr(sub_proj_effective_work_dir);
1456 last_elem->str2 = command;
1457 } else {
1458 ERROR("Internal error: cannot add command to list");
1459 }
1460 }
1461 // add working dir to the end of list
1462 if (sub_project_dirs) {
1463 // go to last element
1464 struct string_list* last_elem = sub_project_dirs;
1465 while (last_elem->next) last_elem = last_elem->next;
1466 // add string to last element if empty or create new last element and add it to that
1467 if (last_elem->str) {
1468 last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list));
1469 last_elem = last_elem->next;
1470 last_elem->next = NULL;
1471 }
1472 autostring cwd_as(get_working_dir());
1473 last_elem->str = (*p_aflag) ? mcopystr(sub_proj_effective_work_dir) : get_relative_dir(sub_proj_effective_work_dir, (const char*)cwd_as);
1474 }
1475 }
1476
1477 for (int z = 0; z < my_argc; ++z) {
1478 if (*p_cflag) {
1479 // central storage, keep in separate container
1480 base_files.add(my_argv[z]); // string was allocated with new
1481 }
1482 else {
1483 const cstring tmp(my_argv[z]);
1484 if (!files.has_key(tmp)){
1485 files.add(tmp, my_argv[z]);
1486 } else {
1487 Free(my_argv[z]);
1488 }
1489 }
1490 }
1491
1492 Free(my_argv); // free the array; we keep the pointers
1493 Free(my_ets);
1494 }
1495 else if (success == TPD_FAILED) {
1496 ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
1497 }
1498 // else TPD_SKIPPED, keep quiet
1499
1500 name = projectLocationURI = NULL; // forget both
1501 }
1502 } // next referenced project
1503 }
1504
1505 if (output_file) {
1506 if (get_path_status(output_file) == PS_DIRECTORY) {
1507 // points to existing dir; use as-is
1508 }
1509 else { // we assume it points to a file: not our problem
1510 output_file = NULL;
1511 }
1512 }
1513
1514 // (argc - optind) is the number of non-option arguments (assumed to be files)
1515 // given on the command line.
1516 int new_argc = local_argc - local_optind + files.size() + base_files.size();
1517 char ** new_argv = (char**)Malloc(sizeof(char*) * new_argc);
1518
1519 int n = 0;
1520
1521 // First, copy the filenames gathered from the TPD
1522 //
1523 // We symlink the files into the working directory
1524 // and pass only the filename to the makefile generator
1525 for (int nf = files.size(); n < nf; ++n) {
1526 const char *fn = files.get_nth_elem(n); // relativeURI to the TPD location
1527 autostring dir_n (get_dir_from_path (fn));
1528 autostring file_n(get_file_from_path(fn));
1529 autostring rel_n (get_absolute_dir(dir_n, abs_tpd_dir));
1530 autostring abs_n (compose_path_name(rel_n, file_n));
1531
1532 if (local_argc == 0) {
1533 // We are being invoked recursively, for a referenced TPD.
1534 // Do not symlink; just return absolute paths to the files.
1535 if (*fn == '/') {
1536 if (*p_cflag) {
1537 // compose with workdir
1538 new_argv[n] = compose_path_name(abs_workdir, file_n);
1539 } else {
1540 // it's an absolute path, copy verbatim
1541 new_argv[n] = mcopystr(fn); // fn will be destroyed, pass a copy
1542 }
1543 }
1544 else { // relative path
1545 if (*p_cflag) {
1546 // compose with workdir
1547 new_argv[n] = compose_path_name(abs_workdir, file_n);
1548 // Do not call file_n.extract() : the composed path will be returned,
1549 // its component will need to be deallocated here.
1550 }
1551 else {
1552 // compose with tpd dir
1553 new_argv[n] = const_cast<char*>(abs_n.extract());
1554 }
1555 }
1556 }
1557 else { // we are processing the top-level TPD
1558 #ifndef MINGW
1559 if (!*p_Pflag) {
1560 int fd = open(abs_n, O_RDONLY);
1561 if (fd >= 0) { // successfully opened
1562 close(fd);
1563 if (output_file) {
1564 file_n = compose_path_name(output_file, file_n);
1565 }
1566 //TODO ! compose with output_file
1567 // save into list: add symlink data to the end of list
1568 if (create_symlink_list) {
1569 // go to last element
1570 struct string2_list* last_elem = create_symlink_list;
1571 while (last_elem->next) last_elem = last_elem->next;
1572 // add strings to last element if empty or create new last element and add it to that
1573 if (last_elem->str1) {
1574 last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list));
1575 last_elem = last_elem->next;
1576 last_elem->next = NULL;
1577 }
1578 last_elem->str1 = mcopystr(abs_n);
1579 last_elem->str2 = mcopystr(file_n);
1580 }
1581 }
1582 else {
1583 ERROR("%s does not exist", (const char*)abs_n);
1584 }
1585 }
1586 #endif
1587 if (*p_Pflag) {
1588 if (*p_aflag) {
1589 puts((const char *)abs_n);
1590 } else {
1591 autostring dir_part(get_dir_from_path(abs_n));
1592 autostring file_part(get_file_from_path(abs_n));
1593 autostring rel_dir_part(get_relative_dir((const char *)dir_part, file_list_path ? file_list_path : (const char *)abs_tpd_dir));
1594 autostring rel_dir_file_part(compose_path_name((const char *)rel_dir_part, (const char *)file_part));
1595 puts((const char *)rel_dir_file_part);
1596 }
1597 }
1598 new_argv[n] = const_cast<char *>(file_n.extract());
1599 }
1600 }
1601 // Print the TPD too.
1602 if (*p_Pflag) {
1603 autostring dir_part(get_dir_from_path(p_tpd_name));
1604 autostring file_part(get_file_from_path(p_tpd_name));
1605 if (*p_aflag) {
1606 puts((const char *)abs_tpd_name);
1607 } else {
1608 autostring rel_dir_part(get_relative_dir(dir_part, file_list_path ? file_list_path : abs_tpd_dir));
1609 autostring rel_dir_file_part(compose_path_name(rel_dir_part, file_part));
1610 const char *rel_tpd_name = (const char *)rel_dir_file_part;
1611 puts(rel_tpd_name);
1612 }
1613 }
1614
1615 // base_files from referenced projects
1616 for (size_t bf = 0, bs = base_files.size(); bf < bs; ++bf, ++n) {
1617 new_argv[n] = base_files[bf];
1618 }
1619 base_files.clear(); // string ownership transfered
1620
1621 // Then, copy the filenames from the command line.
1622 for (int a = *p_optind; a < *p_argc; ++a, ++n) {
1623 // String may be from main's argv; copy to the heap.
1624 new_argv[n] = mcopystr((*p_argv)[a]);
1625 }
1626
1627 if (local_argc > 0) { // it is the outermost call
1628 clear_seen_tpd_files(seen_tpd_files);
1629 }
1630 // replace argv
1631 *p_argv = new_argv;
1632 *p_argc = new_argc;
1633 *p_optind = 0;
1634
1635 // finally...
1636 for (size_t i = 0, e = files.size(); i < e; ++i) {
1637 Free(const_cast<char*>(files.get_nth_elem(i)));
1638 }
1639 files.clear();
1640
1641 for (size_t i = 0, e = folders.size(); i < e; ++i) {
1642 Free(const_cast<char*>(folders.get_nth_elem(i)));
1643 }
1644 folders.clear();
1645
1646 excluded_files.clear();
1647 excluded_folders.clear();
1648 path_vars.clear();
1649
1650 xmlCleanupParser();
1651 // ifdef debug
1652 xmlMemoryDump();
1653 return TPD_SUCCESS;
1654 }
This page took 0.135177 seconds and 4 git commands to generate.