Added 'make test' in the Makefile.in, upon sin.dsp.
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / parser / enrobage.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22
23
24 #include "enrobage.hh"
25 #include <vector>
26 #include <string>
27 #include <limits.h>
28 #include <stdlib.h>
29 #include "compatibility.hh"
30 #include <climits>
31
32 extern string gFaustSuperSuperDirectory;
33 extern string gFaustSuperDirectory;
34 extern string gFaustDirectory;
35 extern string gMasterDirectory;
36 extern string gClassName;
37
38 //----------------------------------------------------------------
39
40
41 /**
42 * Returns true is a line is blank (contains only white caracters)
43 */
44 static bool isBlank(const string& s) {
45 for (size_t i=0; i<s.size(); i++) {
46 if (s[i] != ' ' && s[i] != '\t') return false;
47 }
48 return true;
49 }
50
51
52 /**
53 * Replace every occurrence of oldstr by newstr inside str. str is modified
54 * and returned as reference for convenience
55 */
56 static string& replaceOccurences(string& str, const string& oldstr, const string& newstr)
57 {
58 string::size_type l1 = oldstr.length();
59 string::size_type l2 = newstr.length();
60
61 string::size_type pos = str.find(oldstr);
62 while ( pos != string::npos) {
63 str.replace(pos, l1, newstr);
64 pos = str.find(oldstr, pos + l2);
65 }
66 return str;
67 }
68
69
70 /**
71 * Used when copying architecture files to replace default mydsp
72 * class name with the user specified one
73 */
74 static string& replaceClassName(string& str)
75 {
76 return replaceOccurences(str, "mydsp", gClassName);
77 }
78
79
80 /**
81 * Copy or remove license header. Architecture files can contain a header specifying
82 * the license. If this header contains an exception tag (for example "FAUST COMPILER EXCEPTION")
83 * it is an indication for the compiler to remove the license header from the resulting code.
84 * A header is the first non blank line that begins a comment.
85 */
86 void streamCopyLicense(istream& src, ostream& dst, const string& exceptiontag)
87 {
88 string s;
89 vector<string> H;
90
91 // skip blank lines
92 while (getline(src,s) && isBlank(s)) dst << s << endl;
93
94 // first non blank should start a comment
95 if (s.find("/*")==string::npos) { dst << s << endl; return; }
96
97 // copy the header into H
98 bool remove = false;
99 H.push_back(s);
100
101 while (getline(src,s) && s.find("*/")==string::npos) {
102 H.push_back(s);
103 if (s.find(exceptiontag) != string::npos) remove=true;
104 }
105
106 // copy the header unless explicitely granted to remove it
107 if (!remove) {
108 // copy the header
109 for (unsigned int i=0; i<H.size(); i++) {
110 dst << H[i] << endl;
111 }
112 dst << s << endl;
113 }
114 }
115
116
117 /**
118 * Copy src to dst until specific line.
119 */
120 void streamCopyUntil(istream& src, ostream& dst, const string& until)
121 {
122 string s;
123 while ( getline(src,s) && (s != until) ) dst << replaceClassName(s) << endl;
124 }
125
126 /**
127 * Copy src to dst.
128 */
129 void streamCopy(istream& src, ostream& dst)
130 {
131 string s;
132 while ( getline(src,s)) dst << replaceClassName(s) << endl;
133 }
134
135 /**
136 * Copy src to dst until end
137 */
138 void streamCopyUntilEnd(istream& src, ostream& dst)
139 {
140 string s;
141 while ( getline(src,s) ) dst << replaceClassName(s) << endl;
142 }
143
144
145 /**
146 * Try to open an architecture file searching in various directories
147 */
148 ifstream* open_arch_stream(const char* filename)
149 {
150 char buffer[FAUST_PATH_MAX];
151 char* old = getcwd (buffer, FAUST_PATH_MAX);
152 int err;
153
154 {
155 ifstream* f = new ifstream();
156 f->open(filename, ifstream::in); if (f->is_open()) return f; else delete f;
157 }
158 char *envpath = getenv("FAUST_LIB_PATH");
159 if (envpath!=NULL) {
160 if (chdir(envpath)==0) {
161 ifstream* f = new ifstream();
162 f->open(filename, ifstream::in);
163 if (f->is_open()) return f; else delete f;
164 }
165 }
166 err = chdir(old);
167 if ( (chdir(gFaustDirectory.c_str())==0) && (chdir("architecture")==0) ) {
168 //cout << "enrobage.cpp : 'architecture' directory found in gFaustDirectory" << endl;
169 ifstream* f = new ifstream();
170 f->open(filename, ifstream::in);
171 if (f->good()) return f; else delete f;
172 }
173 err = chdir(old);
174 if ((chdir(gFaustSuperDirectory.c_str())==0) && (chdir("architecture")==0) ) {
175 //cout << "enrobage.cpp : 'architecture' directory found in gFaustSuperDirectory" << endl;
176 ifstream* f = new ifstream();
177 f->open(filename, ifstream::in);
178 if (f->good()) return f; else delete f;
179 }
180 err = chdir(old);
181 if ((chdir(gFaustSuperSuperDirectory.c_str())==0) && (chdir("architecture")==0) ) {
182 //cout << "enrobage.cpp : 'architecture' directory found in gFaustSuperSuperDirectory" << endl;
183 ifstream* f = new ifstream();
184 f->open(filename, ifstream::in);
185 if (f->good()) return f; else delete f;
186 }
187 #ifdef INSTALL_PREFIX
188 err = chdir(old);
189 if (chdir(INSTALL_PREFIX "/lib/faust")==0) {
190 ifstream* f = new ifstream();
191 f->open(filename);
192 if (f->good()) return f; else delete f;
193 }
194 #endif
195 err = chdir(old);
196 if (chdir("/usr/local/lib/faust")==0) {
197 ifstream* f = new ifstream();
198 f->open(filename);
199 if (f->good()) return f; else delete f;
200 }
201 err = chdir(old);
202 if (chdir("/usr/lib/faust")==0) {
203 ifstream* f = new ifstream();
204 f->open(filename);
205 if (f->good()) return f; else delete f;
206 }
207
208 return 0;
209 }
210
211
212
213 /*---------------------------------------------*/
214
215 /**
216 * Check if a file exists.
217 * @return true if the file exist, false otherwise
218 */
219
220 bool check_file(const char* filename)
221 {
222 FILE* f = fopen(filename, "r");
223
224 if (f == NULL) {
225 fprintf(stderr, "faust: "); perror(filename);
226 } else {
227 fclose(f);
228 }
229 return f != NULL;
230 }
231
232
233 /**
234 * Try to open the file '<dir>/<filename>'. If it succeed, it stores the full pathname
235 * of the file into <fullpath>
236 */
237 static FILE* fopenat(string& fullpath, const char* dir, const char* filename)
238 {
239 int err;
240 char olddirbuffer[FAUST_PATH_MAX];
241 char newdirbuffer[FAUST_PATH_MAX];
242
243 char* olddir = getcwd (olddirbuffer, FAUST_PATH_MAX);
244
245 if (chdir(dir) == 0) {
246 FILE* f = fopen(filename, "r");
247 fullpath = getcwd (newdirbuffer, FAUST_PATH_MAX);
248 fullpath += '/';
249 fullpath += filename;
250 err = chdir(olddir);
251 return f;
252 }
253 err = chdir(olddir);
254 return 0;
255 }
256
257 /**
258 * Try to open the file '<dir>/<filename>'. If it succeed, it stores the full pathname
259 * of the file into <fullpath>
260 */
261 static FILE* fopenat(string& fullpath, const string& dir, const char* filename)
262 {
263 return fopenat(fullpath, dir.c_str(), filename);
264 }
265
266 /**
267 * Try to open the file '<dir>/<path>/<filename>'. If it succeed, it stores the full pathname
268 * of the file into <fullpath>
269 */
270 static FILE* fopenat(string& fullpath, const string& dir, const char* path, const char* filename)
271 {
272 int err;
273 char olddirbuffer[FAUST_PATH_MAX];
274 char newdirbuffer[FAUST_PATH_MAX];
275
276 char* olddir = getcwd (olddirbuffer, FAUST_PATH_MAX);
277 if (chdir(dir.c_str()) == 0) {
278 if (chdir(path) == 0) {
279 FILE* f = fopen(filename, "r");
280 fullpath = getcwd (newdirbuffer, FAUST_PATH_MAX);
281 fullpath += '/';
282 fullpath += filename;
283 err = chdir(olddir);
284 return f;
285 }
286 }
287 err = chdir(olddir);
288 return 0;
289 }
290
291
292
293 /**
294 * Test absolute pathname.
295 */
296 static bool isAbsolutePathname(const string& filename)
297 {
298 //test windows absolute pathname "x:xxxxxx"
299 if (filename.size()>1 && filename[1] == ':') return true;
300
301 // test unix absolute pathname "/xxxxxx"
302 if (filename.size()>0 && filename[0] == '/') return true;
303
304 return false;
305 }
306
307
308 /**
309 * Build a full pathname of <filename>.
310 * <fullpath> = <currentdir>/<filename>
311 */
312 static void buildFullPathname(string& fullpath, const char* filename)
313 {
314 char old[FAUST_PATH_MAX];
315
316 if (isAbsolutePathname(filename)) {
317 fullpath = filename;
318 } else {
319 fullpath = getcwd (old, FAUST_PATH_MAX);
320 fullpath += '/';
321 fullpath += filename;
322 }
323 }
324
325 /**
326 * Try to open the file <filename> searching in various directories. If succesful
327 * place its full pathname in the string <fullpath>
328 */
329
330 #ifdef WIN32
331 FILE* fopensearch(const char* filename, string& fullpath)
332 {
333 FILE* f;
334 char* envpath;
335
336 if ((f = fopen(filename, "r"))) {
337 buildFullPathname(fullpath, filename);
338 return f;
339 }
340 if ((f = fopenat(fullpath, gMasterDirectory, filename))) {
341 return f;
342 }
343 if ((envpath = getenv("FAUST_LIB_PATH")) && (f = fopenat(fullpath, envpath, filename))) {
344 return f;
345 }
346 if ((f = fopenat(fullpath, gFaustDirectory, "architecture", filename))) {
347 return f;
348 }
349 if ((f = fopenat(fullpath, gFaustSuperDirectory, "architecture", filename))) {
350 return f;
351 }
352 if ((f = fopenat(fullpath, gFaustSuperSuperDirectory, "architecture", filename))) {
353 return f;
354 }
355 return 0;
356 }
357 #else
358 FILE* fopensearch(const char* filename, string& fullpath)
359 {
360 FILE* f;
361 char* envpath;
362
363 if ((f = fopen(filename, "r"))) {
364 buildFullPathname(fullpath, filename);
365 return f;
366 }
367 if ((f = fopenat(fullpath, gMasterDirectory, filename))) {
368 return f;
369 }
370 if ((envpath = getenv("FAUST_LIB_PATH")) && (f = fopenat(fullpath, envpath, filename))) {
371 return f;
372 }
373 if ((f = fopenat(fullpath, gFaustDirectory, "architecture", filename))) {
374 return f;
375 }
376 if ((f = fopenat(fullpath, gFaustSuperDirectory, "architecture", filename))) {
377 return f;
378 }
379 if ((f = fopenat(fullpath, gFaustSuperSuperDirectory, "architecture", filename))) {
380 return f;
381 }
382 #ifdef INSTALL_PREFIX
383 if ((f = fopenat(fullpath, INSTALL_PREFIX "/lib/faust", filename))) {
384 return f;
385 }
386 #endif
387 if ((f = fopenat(fullpath, "/usr/local/lib/faust", filename))) {
388 return f;
389 }
390 if ((f = fopenat(fullpath, "/usr/lib/faust", filename))) {
391 return f;
392 }
393 return 0;
394 }
395 #endif
396
397
398 /**
399 * filebasename returns the basename of a path.
400 * (adapted by kb from basename.c)
401 *
402 * @param[in] The path to parse.
403 * @return The last component of the given path.
404 */
405 #ifndef DIR_SEPARATOR
406 #define DIR_SEPARATOR '/'
407 #endif
408
409 #ifdef WIN32
410 #define HAVE_DOS_BASED_FILE_SYSTEM
411 #ifndef DIR_SEPARATOR_2
412 #define DIR_SEPARATOR_2 '\\'
413 #endif
414 #endif
415
416 /* Define IS_DIR_SEPARATOR. */
417 #ifndef DIR_SEPARATOR_2
418 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
419 #else /* DIR_SEPARATOR_2 */
420 # define IS_DIR_SEPARATOR(ch) \
421 (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
422 #endif /* DIR_SEPARATOR_2 */
423
424
425 /**
426 * returns a pointer on the basename part of name
427 */
428 const char* filebasename(const char* name)
429 {
430 #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
431 /* Skip over the disk name in MSDOS pathnames. */
432 if (isalpha(name[0]) && name[1] == ':')
433 name += 2;
434 #endif
435
436 const char* base;
437 for (base = name; *name; name++)
438 {
439 if (IS_DIR_SEPARATOR (*name))
440 {
441 base = name + 1;
442 }
443 }
444 return base;
445 }
446
447
448 /**
449 * returns a string containing the dirname of name
450 * If no dirname, returns "."
451 */
452 string filedirname(const string& name)
453 {
454 const char* base = filebasename(name.c_str());
455 const unsigned int size = base-name.c_str();
456 string dirname;
457
458 if (size==0) {
459 dirname += '.';
460
461 } else if (size==1) {
462 dirname += name[0];
463
464 } else {
465 for (unsigned int i=0; i<size-1; i++) {
466 dirname += name[i];
467 }
468 }
469 return dirname;
470 }