|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 #include "CdlTkPriv.h" |
|
18 |
|
19 #include <string> |
|
20 #include <vector> |
|
21 #include <algorithm> |
|
22 #include <iostream> |
|
23 #include <fstream> |
|
24 #include <sstream> |
|
25 #include <iomanip> |
|
26 #include <direct.h> |
|
27 using namespace std; |
|
28 |
|
29 namespace CdlCompilerToolkit { |
|
30 |
|
31 // |
|
32 // CdlCompilerToolkitErr |
|
33 // |
|
34 |
|
35 CdlCompilerToolkitErr::~CdlCompilerToolkitErr() |
|
36 { |
|
37 } |
|
38 |
|
39 |
|
40 // |
|
41 // CCdlTkFileCleanup |
|
42 // |
|
43 |
|
44 CCdlTkFileCleanup::CCdlTkFileCleanup() |
|
45 : iName("") |
|
46 { |
|
47 } |
|
48 |
|
49 CCdlTkFileCleanup::CCdlTkFileCleanup(const std::string& aName) |
|
50 : iName(aName) |
|
51 { |
|
52 } |
|
53 |
|
54 CCdlTkFileCleanup::~CCdlTkFileCleanup() |
|
55 { |
|
56 Cleanup(); |
|
57 } |
|
58 |
|
59 void CCdlTkFileCleanup::Set(const string& aName) |
|
60 { |
|
61 iName = aName; |
|
62 } |
|
63 |
|
64 void CCdlTkFileCleanup::Cleanup() |
|
65 { |
|
66 if (!iName.empty()) |
|
67 CdlTkUtil::DeleteFile(iName); |
|
68 Release(); |
|
69 } |
|
70 |
|
71 string CCdlTkFileCleanup::Name() const |
|
72 { |
|
73 return iName; |
|
74 } |
|
75 |
|
76 void CCdlTkFileCleanup::Release() |
|
77 { |
|
78 iName.erase(); |
|
79 } |
|
80 |
|
81 |
|
82 // |
|
83 // CdlTkAssert |
|
84 // |
|
85 |
|
86 CdlTkAssert::CdlTkAssert(const string& aText) |
|
87 : iText(aText) |
|
88 { |
|
89 } |
|
90 |
|
91 void CdlTkAssert::Show(ostream& stream) const |
|
92 { |
|
93 stream << "Cdl Compiler Toolkit assertion failed : " << iText << endl; |
|
94 } |
|
95 |
|
96 |
|
97 // |
|
98 // CdlTkFileOpenErr |
|
99 // |
|
100 |
|
101 CdlTkFileOpenErr::CdlTkFileOpenErr(const string& aFileName) : iFileName(aFileName) |
|
102 { |
|
103 } |
|
104 |
|
105 void CdlTkFileOpenErr::Show(ostream& stream) const |
|
106 { |
|
107 stream << endl; |
|
108 stream << iFileName << " failed to open" << endl; |
|
109 } |
|
110 |
|
111 |
|
112 // |
|
113 // CdlTkUtil |
|
114 // |
|
115 |
|
116 string CdlTkUtil::CurrentDrive() |
|
117 { |
|
118 static string drive = "?:"; |
|
119 if (drive == "?:") |
|
120 drive[0] = 'A' + _getdrive() - 1; |
|
121 return drive; |
|
122 } |
|
123 |
|
124 string CdlTkUtil::CurrentDir() |
|
125 { |
|
126 static string dir = ""; |
|
127 if (dir == "") |
|
128 { |
|
129 char buf[256]; |
|
130 dir = _getcwd(buf, 255) + 2; // +2 removes drive |
|
131 dir += "\\"; |
|
132 } |
|
133 return dir; |
|
134 } |
|
135 |
|
136 static string gOutputPath = ""; |
|
137 |
|
138 string CdlTkUtil::OutputPath() |
|
139 { |
|
140 if (gOutputPath == "") |
|
141 gOutputPath = CurrentDir(); |
|
142 return gOutputPath; |
|
143 } |
|
144 |
|
145 void CdlTkUtil::SetOutputPath(const string& aPath) |
|
146 { |
|
147 gOutputPath = aPath; |
|
148 if (gOutputPath.size() == 0) |
|
149 gOutputPath += ".\\"; |
|
150 else if (gOutputPath[gOutputPath.size()-1] != '\\') |
|
151 gOutputPath += "\\"; // CDL Tk convention is that paths always end in \ |
|
152 } |
|
153 |
|
154 string CdlTkUtil::ToLower(const string& aString) |
|
155 { |
|
156 string r; |
|
157 r.resize(aString.size()); |
|
158 transform(aString.begin(), aString.end(), r.begin(), tolower); |
|
159 return r; |
|
160 } |
|
161 |
|
162 string CdlTkUtil::ToUpper(const string& aString) |
|
163 { |
|
164 string r; |
|
165 r.resize(aString.size()); |
|
166 transform(aString.begin(), aString.end(), r.begin(), toupper); |
|
167 return r; |
|
168 } |
|
169 |
|
170 string CdlTkUtil::ToCpp(const string& aString) |
|
171 { |
|
172 string r = aString; |
|
173 for (string::iterator pC = r.begin(); pC != r.end(); ++pC) |
|
174 { |
|
175 if (!CdlTkUtil::IsCpp(*pC)) |
|
176 *pC = '_'; |
|
177 } |
|
178 if (r.empty() || CdlTkUtil::IsNumeric(r[0])) |
|
179 r = string("_") + r; |
|
180 return r; |
|
181 } |
|
182 |
|
183 string CdlTkUtil::StripPath(const string& aPath) |
|
184 { |
|
185 return aPath.substr(aPath.rfind('\\')+1); |
|
186 } |
|
187 |
|
188 string CdlTkUtil::ResolvePath(const string& aPath, const string& aFileName) |
|
189 { |
|
190 int size = aFileName.size(); |
|
191 // if aFileName is absolute, return it |
|
192 if (size > 0 && aFileName[0] == '\\' || size > 1 && aFileName[1] == ':') |
|
193 return aFileName; |
|
194 |
|
195 string path = aPath; |
|
196 string file = aFileName; |
|
197 |
|
198 // while file starts with a '.', chop file head directory and path tail directory if necessary |
|
199 while (file.size() > 0 && file[0]=='.') |
|
200 { |
|
201 // if file starts with a "..", chop the tail directory off the path |
|
202 if (file.size() > 1 && file[1]=='.' && !path.empty()) |
|
203 { |
|
204 path.resize(path.size()-1); // remove the last slash |
|
205 path.resize(path.rfind('\\')+1); // remove everything after the next last slash |
|
206 } |
|
207 |
|
208 // chop the head directory off the file - it has to have a '\' if it has a '.' |
|
209 int fileSlashPos = file.find('\\'); |
|
210 if (fileSlashPos == string::npos) |
|
211 throw CdlTkAssert("Illegal filename"); |
|
212 file = file.substr(fileSlashPos + 1); |
|
213 } |
|
214 |
|
215 // join remaining path and file |
|
216 return path + file; |
|
217 } |
|
218 |
|
219 string CdlTkUtil::CapitalizeFilename(const string& aString) |
|
220 { |
|
221 // convert the whole thing to lower case |
|
222 string res = ToLower(aString); |
|
223 // find the first character after the last \ - will be 0 if no \ is present. |
|
224 int filenamePos = res.find_last_of('\\') + 1; |
|
225 if (filenamePos >= res.size()) |
|
226 throw CdlTkAssert(aString + " has no filename"); |
|
227 // uppercase the first character |
|
228 res[filenamePos] = toupper(res[filenamePos]); |
|
229 cerr << "Warning, filename capitalized: " << res << endl; |
|
230 return res; |
|
231 } |
|
232 |
|
233 string CdlTkUtil::CorrectFilenameCase(const string& aString) |
|
234 { |
|
235 // The current standard is to set the filename and path to lower case. |
|
236 return ToLower(aString); |
|
237 } |
|
238 |
|
239 string CdlTkUtil::Replace(const string& aTarget, const string& aWith, const string& aIn) |
|
240 { |
|
241 string ret; |
|
242 int pos=0; |
|
243 int lastMatch = 0; |
|
244 int targetMatch = 0; |
|
245 int targetSize = aTarget.size(); |
|
246 int inSize = aIn.size(); |
|
247 while (pos < inSize) |
|
248 { |
|
249 if (aTarget[targetMatch] == aIn[pos++]) |
|
250 { |
|
251 ++targetMatch; |
|
252 if (targetMatch == targetSize) |
|
253 { |
|
254 AppendString(ret, aIn.substr(lastMatch, pos - targetMatch - lastMatch)); |
|
255 AppendString(ret, aWith); |
|
256 lastMatch = pos; |
|
257 targetMatch = 0; |
|
258 } |
|
259 } |
|
260 else |
|
261 { |
|
262 targetMatch = 0; |
|
263 } |
|
264 } |
|
265 AppendString(ret, aIn.substr(lastMatch)); |
|
266 return ret; |
|
267 } |
|
268 |
|
269 void CdlTkUtil::ExportFile(CCdlTkFileCleanup& aSourceFile, const string& aExport, ios_base::openmode aOpenMode) |
|
270 { |
|
271 if (!FilesAreIdentical(aSourceFile.Name(), aExport, aOpenMode)) |
|
272 { |
|
273 CopyFile(aSourceFile.Name(), aExport, aOpenMode); |
|
274 } |
|
275 aSourceFile.Cleanup(); |
|
276 } |
|
277 |
|
278 void CdlTkUtil::ExportFileIfWritable(CCdlTkFileCleanup& aSourceFile, const string& aExport, ios_base::openmode aOpenMode) |
|
279 { |
|
280 if (!FilesAreIdentical(aSourceFile.Name(), aExport, aOpenMode)) |
|
281 { |
|
282 try |
|
283 { |
|
284 CopyFile(aSourceFile.Name(), aExport, aOpenMode); |
|
285 } |
|
286 catch (const CdlTkFileOpenErr& /*e*/) |
|
287 { |
|
288 cerr << "Could not write to " << aExport << endl; |
|
289 } |
|
290 } |
|
291 aSourceFile.Cleanup(); |
|
292 } |
|
293 |
|
294 void CdlTkUtil::DeleteFile(const std::string& aFileName) |
|
295 { |
|
296 remove(aFileName.c_str()); |
|
297 } |
|
298 |
|
299 void CdlTkUtil::CopyFile(const std::string& aSourceFileName, const std::string& aDestinationFileName, ios_base::openmode aOpenMode) |
|
300 { |
|
301 ifstream from; |
|
302 OpenInput(from, aSourceFileName, aOpenMode); |
|
303 ofstream to; |
|
304 OpenOutput(to, aDestinationFileName, aOpenMode); |
|
305 |
|
306 const int KSize = 1024; |
|
307 char buf[KSize+1]; |
|
308 while (!from.eof()) |
|
309 { |
|
310 from.read(buf,KSize); |
|
311 to.write(buf, from.gcount()); |
|
312 } |
|
313 |
|
314 from.close(); |
|
315 to.close(); |
|
316 } |
|
317 |
|
318 bool CdlTkUtil::FilesAreIdentical(const std::string& aLeftFileName, const std::string& aRightFileName, ios_base::openmode aOpenMode) |
|
319 { |
|
320 bool different = false; |
|
321 ifstream leftFile(aLeftFileName.c_str(), aOpenMode); |
|
322 ifstream rightFile(aRightFileName.c_str(), aOpenMode); |
|
323 |
|
324 const int KSize = 1024; |
|
325 char left[KSize+1]; |
|
326 char right[KSize+1]; |
|
327 |
|
328 while (!leftFile.eof() && !rightFile.eof()) |
|
329 { |
|
330 int gotLeft = leftFile.read(left,KSize).gcount(); |
|
331 int gotRight = rightFile.read(right,KSize).gcount(); |
|
332 |
|
333 if (gotLeft != gotRight || memcmp(left, right, gotLeft) != 0) |
|
334 { |
|
335 different = true; |
|
336 break; |
|
337 } |
|
338 } |
|
339 |
|
340 if (leftFile.eof() != rightFile.eof()) |
|
341 different = true; |
|
342 |
|
343 leftFile.close(); |
|
344 rightFile.close(); |
|
345 |
|
346 return !different; |
|
347 } |
|
348 |
|
349 void CdlTkUtil::OpenTempOutput(ofstream& aStream, CCdlTkFileCleanup& aFile, ios_base::openmode aOpenMode) |
|
350 { |
|
351 char tmpName[256]; |
|
352 if (!tmpnam(tmpName)) |
|
353 { |
|
354 throw CdlTkAssert("Can't create temporary file name"); |
|
355 } |
|
356 |
|
357 OpenOutput(aStream, tmpName, aOpenMode); |
|
358 aFile.Set(tmpName); |
|
359 } |
|
360 |
|
361 void CdlTkUtil::OpenOutput(ofstream& aStream, const string& aFileName, ios_base::openmode aOpenMode) |
|
362 { |
|
363 aStream.open(aFileName.c_str(), aOpenMode); |
|
364 if (!aStream.is_open()) |
|
365 { |
|
366 throw CdlTkFileOpenErr(aFileName); |
|
367 } |
|
368 } |
|
369 |
|
370 void CdlTkUtil::OpenInput(ifstream& aStream, const string& aFileName, ios_base::openmode aOpenMode) |
|
371 { |
|
372 aStream.open(aFileName.c_str(), aOpenMode); |
|
373 if (!aStream.is_open()) |
|
374 throw CdlTkFileOpenErr(aFileName); |
|
375 } |
|
376 |
|
377 int CdlTkUtil::ParseInt(const string& aInt) |
|
378 { |
|
379 int base = 10; |
|
380 if (aInt.size() > 1 && aInt[0] == '0') |
|
381 { |
|
382 base = 8; |
|
383 if (aInt[1] == 'x') |
|
384 base = 16; |
|
385 } |
|
386 |
|
387 int val = 0; |
|
388 stringstream s(aInt); |
|
389 s >> setbase(base) >> val; |
|
390 return val; |
|
391 } |
|
392 |
|
393 string CdlTkUtil::IntToString(int aInt) |
|
394 { |
|
395 stringstream s; |
|
396 s << aInt; |
|
397 return s.str(); |
|
398 } |
|
399 |
|
400 string CdlTkUtil::IntToHexString(int aInt) |
|
401 { |
|
402 stringstream s; |
|
403 s << "0x" << setw(8) << setfill('0') << hex << aInt; |
|
404 return s.str(); |
|
405 } |
|
406 |
|
407 char* gHexDigits = "0123456789abcdef"; |
|
408 string CdlTkUtil::ShortToHexString(short aInt) |
|
409 { |
|
410 char s[7] = "0x0000"; |
|
411 s[2]=gHexDigits[(aInt>>12)&0xf]; |
|
412 s[3]=gHexDigits[(aInt>>8)&0xf]; |
|
413 s[4]=gHexDigits[(aInt>>4)&0xf]; |
|
414 s[5]=gHexDigits[aInt&0xf]; |
|
415 return s; |
|
416 } |
|
417 |
|
418 string CdlTkUtil::CharToHexString(char aInt) |
|
419 { |
|
420 char s[5] = "0x00"; |
|
421 s[2]=gHexDigits[(aInt>>4)&0xf]; |
|
422 s[3]=gHexDigits[aInt&0xf]; |
|
423 return s; |
|
424 } |
|
425 |
|
426 void CdlTkUtil::StripLeadingAndTrailingWhitespace(string& aStr) |
|
427 { |
|
428 int pos = aStr.find_first_not_of(KWhiteSpace); |
|
429 if (pos == string::npos) |
|
430 { |
|
431 aStr = KEmptyString; |
|
432 } |
|
433 else |
|
434 { |
|
435 aStr = aStr.substr(pos, aStr.find_last_not_of(KWhiteSpace) + 1 - pos); |
|
436 } |
|
437 } |
|
438 |
|
439 bool CdlTkUtil::IsAlpha(char aChar) |
|
440 { |
|
441 return ('A' <= aChar && aChar <= 'Z') || ('a' <= aChar && aChar <= 'z'); |
|
442 } |
|
443 |
|
444 bool CdlTkUtil::IsNumeric(char aChar) |
|
445 { |
|
446 return '0' <= aChar && aChar <= '9'; |
|
447 } |
|
448 |
|
449 bool CdlTkUtil::IsCpp(char aChar) |
|
450 { |
|
451 return IsAlpha(aChar) || IsNumeric(aChar) || aChar == '_'; |
|
452 } |
|
453 |
|
454 void ZeroInts(int* aInts, int aCount) |
|
455 { |
|
456 for (int ii=0; ii<aCount; ii++) |
|
457 aInts[ii] = 0; |
|
458 } |
|
459 |
|
460 string CdlTkUtil::MultiReplace(const CReplaceSet& aSet, const string& aIn) |
|
461 { |
|
462 string ret; |
|
463 int setCount = aSet.size(); |
|
464 int* match = new int[setCount]; |
|
465 if (!match) |
|
466 throw bad_alloc(); |
|
467 ZeroInts(match, setCount); |
|
468 |
|
469 int inSize = aIn.size(); |
|
470 int pos = 0; |
|
471 int lastMatch = 0; |
|
472 while (pos < inSize) |
|
473 { |
|
474 char ch = aIn[pos++]; |
|
475 for (int ii=0; ii<setCount; ii++) |
|
476 { |
|
477 const string& target = aSet[ii].first; |
|
478 int& targetMatch = match[ii]; |
|
479 if (target[targetMatch] == ch) |
|
480 { |
|
481 ++targetMatch; |
|
482 if (targetMatch == target.size()) |
|
483 { |
|
484 AppendString(ret, aIn.substr(lastMatch, pos - targetMatch - lastMatch)); |
|
485 AppendString(ret, aSet[ii].second); |
|
486 lastMatch = pos; |
|
487 ZeroInts(match, setCount); |
|
488 } |
|
489 } |
|
490 else |
|
491 { |
|
492 match[ii] = 0; |
|
493 } |
|
494 } |
|
495 } |
|
496 AppendString(ret, aIn.substr(lastMatch)); |
|
497 |
|
498 delete[] match; |
|
499 return ret; |
|
500 } |
|
501 |
|
502 void CdlTkUtil::AppendString(string& aTarget, const string& aAppend) |
|
503 { |
|
504 int resSize = aTarget.size() + aAppend.size(); |
|
505 if (aTarget.capacity() < resSize) |
|
506 aTarget.reserve(resSize*2); |
|
507 aTarget.append(aAppend); |
|
508 } |
|
509 |
|
510 static string gCommandLine = ""; |
|
511 |
|
512 string CdlTkUtil::CommandLine() |
|
513 { |
|
514 return gCommandLine; |
|
515 } |
|
516 |
|
517 void CdlTkUtil::SetCommandLine(int argc, char* argv[]) |
|
518 { |
|
519 string tool(argv[0]); |
|
520 tool = tool.substr(tool.find_last_of('\\') + 1); |
|
521 gCommandLine = tool.substr(0, tool.find_last_of('.')); |
|
522 for (int ii=1; ii<argc; ii++) |
|
523 { |
|
524 AppendString(gCommandLine, " "); |
|
525 AppendString(gCommandLine, argv[ii]); |
|
526 } |
|
527 } |
|
528 |
|
529 // |
|
530 // CdlTkUtil::CReplaceSet |
|
531 // |
|
532 |
|
533 void CdlTkUtil::CReplaceSet::Add(const string& aTarget, const string& aWith) |
|
534 { |
|
535 push_back(make_pair(aTarget, aWith)); |
|
536 } |
|
537 |
|
538 void CdlTkUtil::ReadFile(std::string& aContent, const std::string& aFileName) |
|
539 { |
|
540 ifstream in; |
|
541 OpenInput(in, aFileName); |
|
542 aContent.erase(); |
|
543 const int KChars = 1024 + 1; |
|
544 char buf[KChars]; |
|
545 while (!in.eof()) |
|
546 { |
|
547 in.get(buf,KChars,0); |
|
548 AppendString(aContent, buf); |
|
549 } |
|
550 in.close(); |
|
551 } |
|
552 |
|
553 void CdlTkUtil::WriteFile(const std::string& aContent, const std::string& aFileName) |
|
554 { |
|
555 ofstream out; |
|
556 OpenOutput(out, aFileName); |
|
557 out << aContent; |
|
558 out.close(); |
|
559 } |
|
560 |
|
561 } // end of namespace CdlCompilerToolkit |