1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <iomanip>
26 #include <iostream>
27 #include <limits>
28 #include <sstream>
29 #include <string>
30 #include <vector>
31 #include <algorithm>
32 
33 #include "Text.hh"
34 #include "compatibility.hh"
35 #include "floats.hh"
36 #include "global.hh"
37 
38 static string substitution(const string& model, const vector<string>& args);
39 
40 /**
41  * Text substitution. Creates a string by replacing all the $n
42  * occurences in the model string, with the corresponding arguments.
43  * Example : subst("float $0 = $1;", "var", T(10.2))
44  */
subst(const string & model,const vector<string> & args)45 string subst(const string& model, const vector<string>& args)
46 {
47     return substitution(model, args);
48 }
49 
subst(const string & model,const string & a0)50 string subst(const string& model, const string& a0)
51 {
52     vector<string> args(10);
53     args[0] = a0;
54     return substitution(model, args);
55 }
56 
subst(const string & model,const string & a0,const string & a1)57 string subst(const string& model, const string& a0, const string& a1)
58 {
59     vector<string> args(10);
60     args[0] = a0;
61     args[1] = a1;
62     return substitution(model, args);
63 }
64 
subst(const string & model,const string & a0,const string & a1,const string & a2)65 string subst(const string& model, const string& a0, const string& a1, const string& a2)
66 {
67     vector<string> args(10);
68     args[0] = a0;
69     args[1] = a1;
70     args[2] = a2;
71     return substitution(model, args);
72 }
73 
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3)74 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3)
75 {
76     vector<string> args(10);
77     args[0] = a0;
78     args[1] = a1;
79     args[2] = a2;
80     args[3] = a3;
81     return substitution(model, args);
82 }
83 
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4)84 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
85              const string& a4)
86 {
87     vector<string> args(10);
88     args[0] = a0;
89     args[1] = a1;
90     args[2] = a2;
91     args[3] = a3;
92     args[4] = a4;
93     return substitution(model, args);
94 }
95 
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4,const string & a5)96 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
97              const string& a4, const string& a5)
98 {
99     vector<string> args(10);
100     args[0] = a0;
101     args[1] = a1;
102     args[2] = a2;
103     args[3] = a3;
104     args[4] = a4;
105     args[5] = a5;
106     return substitution(model, args);
107 }
108 
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4,const string & a5,const string & a6)109 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
110              const string& a4, const string& a5, const string& a6)
111 {
112     vector<string> args(10);
113     args[0] = a0;
114     args[1] = a1;
115     args[2] = a2;
116     args[3] = a3;
117     args[4] = a4;
118     args[5] = a5;
119     args[6] = a6;
120     return substitution(model, args);
121 }
122 
substitution(const string & model,const vector<string> & args)123 static string substitution(const string& model, const vector<string>& args)
124 {
125     char   c;
126     int    i = 0, ilast = (int)model.length() - 1;
127     string result;
128     while (i < ilast) {
129         c = model[i++];
130         if (c != '$') {
131             result += c;
132         } else {
133             c = model[i++];
134             if (c >= '0' && c <= '9') {
135                 result += args[c - '0'];
136             } else {
137                 result += c;
138             }
139         }
140     }
141     if (i == ilast) result += model[i];
142     return result;
143 }
144 
T(char * c)145 string T(char* c)
146 {
147     return string(c);
148 }
149 
T(int n)150 string T(int n)
151 {
152     char c[64];
153     snprintf(c, 63, "%d", n);
154     return string(c);
155 }
156 
T(long n)157 string T(long n)
158 {
159     char c[64];
160     snprintf(c, 63, "%ld", n);
161     return string(c);
162 }
163 
164 /**
165  * If needed add a trailing '.0' to the
166  * the textual representation of a floating point number
167  * to avoid confusions with an int.
168  */
ensureFloat(const string & c)169 static string ensureFloat(const string& c)
170 {
171     bool isInt = true;
172     for (size_t i = 0; i < c.size(); i++) {
173         if ((c[i] == '.') || (c[i] == 'e')) {
174             isInt = false;
175             break;
176         }
177     }
178     return (isInt) ? (c + ".0") : c;
179 }
180 
181 /**
182  * Special encoding for Julia float numbers, see:
183  * https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/#Floating-Point-Numbers
184  */
encodeJuliaFloat(const string & c,bool & need_suffix)185 static string encodeJuliaFloat(const string& c, bool& need_suffix)
186 {
187     bool isInt = true;
188     string res;
189     for (size_t i = 0; i < c.size(); i++) {
190         if ((c[i] == '.') || (c[i] == 'e')) {
191             isInt = false;
192         }
193         if (c[i] == 'e') {
194             res += 'f';
195             need_suffix = false;
196         } else {
197             res += c[i];
198         }
199     }
200     return (isInt) ? (res + ".0") : res;
201 }
202 
203 /**
204  * Convert a REAL (float/double) into a string.
205  * Adjusts the precision p to the needs.
206  */
207 template <typename REAL>
TAux(REAL n)208 static string TAux(REAL n)
209 {
210     stringstream num;
211     num << setprecision(numeric_limits<REAL>::max_digits10) << n;
212     if (gGlobal->gOutputLang == "julia") {
213         bool need_suffix = true;
214         string res = encodeJuliaFloat(num.str(), need_suffix);
215         return (need_suffix) ? (res + inumix()) : res;
216     } else {
217         return ensureFloat(num.str()) + inumix();
218     }
219 }
220 
221 /**
222  * Convert a single-precision float into a string.
223  * Adjusts the precision p to the needs.
224  */
T(float n)225 string T(float n) { return TAux<float>(n); }
226 
227 /**
228 * Convert a double-precision float into a string.
229 * Adjusts the precision p to the needs.
230 */
T(double n)231 string T(double n) { return TAux<double>(n); }
232 
233 /**
234  * remove quotes from a string
235  */
unquote(const string & str)236 string unquote(const string& str)
237 {
238     return (str[0] == '"') ? str.substr(1, str.size() - 2) : str;
239 }
240 
241 /**
242  * add quotes to a string
243  */
quote(const string & s)244 string quote(const string& s)
245 {
246     return "\"" + s + "\"";
247 }
248 
249 /**
250  * Print n tabs (for indentation purpose)
251  * @param n number of tabs to print
252  * @param fout output stream
253  */
tab(int n,ostream & fout)254 void tab(int n, ostream& fout)
255 {
256     fout << '\n';
257     while (n--) fout << '\t';
258 }
259 
back(int n,ostream & fout)260 void back(int n, ostream& fout)
261 {
262     long pos = fout.tellp();
263     fout.seekp(pos-n);
264 }
265 
266 /**
267  * Print a list of lines
268  * @param n number of tabs of indentation
269  * @param lines list of lines to be printed
270  * @param fout output stream
271  */
printlines(int n,list<string> & lines,ostream & fout,const string & sep)272 void printlines(int n, list<string>& lines, ostream& fout, const string& sep)
273 {
274     list<string>::const_iterator s;
275     for (s = lines.begin(); s != lines.end(); s++) {
276         if (s == lines.begin()) {
277             tab(n, fout);
278             fout << *s;  // No separator before first one
279         } else {
280             tab(n, fout);
281             fout << sep << *s;
282         }
283     }
284 }
285 
286 /**
287  * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
288  * (but not those in the middle of the string)
289  */
290 
rmWhiteSpaces(const string & s)291 string rmWhiteSpaces(const string& s)
292 {
293     size_t i = s.find_first_not_of(" \t");
294     size_t j = s.find_last_not_of(" \t");
295     if ((i != string::npos) & (j != string::npos)) {
296         return s.substr(i, 1 + j - i);
297     } else {
298         return "";
299     }
300 }
301 
302 // 'Quad' (= long double) are currectly treated like 'double'
303 
checkReal(double val)304 string checkReal(double val)
305 {
306     return (strcmp(ifloat(), "float") == 0) ? checkFloat(float(val)) : checkDouble(val);
307 }
308 
indent(const string & str,int tabs)309 string indent(const string& str, int tabs)
310 {
311     stringstream instream(str);
312     stringstream outstream;
313     string       line;
314     while (getline(instream, line, '\n')) {
315         for (int i = 0; i != tabs; ++i) {
316             outstream << '\t';
317         }
318         outstream << line << endl;
319     }
320     return outstream.str();
321 }
322 
replaceChar(string str,char src,char dst)323 string replaceChar(string str, char src, char dst)
324 {
325     replace(str.begin(), str.end(), src, dst);
326     return str;
327 }
328 
replaceCharList(string str,const vector<char> & ch1,char ch2)329 string replaceCharList(string str, const vector<char>& ch1, char ch2)
330 {
331     vector<char>::const_iterator beg = ch1.begin();
332     vector<char>::const_iterator end = ch1.end();
333     for (size_t i = 0; i < str.length(); ++i) {
334         if (find(beg, end, str[i]) != end) {
335             str[i] = ch2;
336         }
337     }
338     return str;
339 }
340 
tokenizeString(const string & str,char sep)341 vector<string> tokenizeString(const string& str, char sep)
342 {
343     vector<string> res;
344     istringstream is(str);
345     string token;
346     while (getline(is, token, sep)) res.push_back(token);
347     return res;
348 }
349 
350