summaryrefslogtreecommitdiff
path: root/cpp/src/Slice/SliceUtil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Slice/SliceUtil.cpp')
-rw-r--r--cpp/src/Slice/SliceUtil.cpp433
1 files changed, 433 insertions, 0 deletions
diff --git a/cpp/src/Slice/SliceUtil.cpp b/cpp/src/Slice/SliceUtil.cpp
new file mode 100644
index 00000000000..e0c490fa937
--- /dev/null
+++ b/cpp/src/Slice/SliceUtil.cpp
@@ -0,0 +1,433 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Slice/Util.h>
+#include <IceUtil/FileUtil.h>
+#include <IceUtil/StringUtil.h>
+#include <climits>
+
+#ifndef _MSC_VER
+# include <unistd.h> // For readlink()
+#endif
+
+using namespace std;
+using namespace Slice;
+
+namespace
+{
+
+string
+normalizePath(const string& path)
+{
+ string result = path;
+
+ replace(result.begin(), result.end(), '\\', '/');
+
+ string::size_type startReplace = 0;
+#ifdef _WIN32
+ //
+ // For UNC paths we need to ensure they are in the format that is
+ // returned by MCPP. IE. "//MACHINE/PATH"
+ //
+ if(result.find("//") == 0)
+ {
+ startReplace = 2;
+ }
+#endif
+ string::size_type pos;
+ while((pos = result.find("//", startReplace)) != string::npos)
+ {
+ result.replace(pos, 2, "/");
+ }
+ pos = 0;
+ while((pos = result.find("/./", pos)) != string::npos)
+ {
+ result.erase(pos, 2);
+ }
+ pos = 0;
+ while((pos = result.find("/..", pos)) != string::npos)
+ {
+ string::size_type last = result.find_last_of("/", pos - 1);
+ if(last != string::npos && result.substr(last, 4) != "/../")
+ {
+ result.erase(last, pos - last + 3);
+ pos = last;
+ }
+ else
+ {
+ ++pos;
+ }
+ }
+
+ if(result.size() > 1) // Remove trailing "/" or "/."
+ {
+ if(result[result.size() - 1] == '/')
+ {
+ result.erase(result.size() - 1);
+ }
+ else if(result[result.size() - 2] == '/' && result[result.size() - 1] == '.')
+ {
+ result.erase(result.size() - (result.size() == 2 ? 1 : 2));
+ }
+ }
+ return result;
+}
+
+}
+
+string
+Slice::fullPath(const string& path)
+{
+ //
+ // This function returns the canonicalized absolute pathname of
+ // the given path.
+ //
+ // It is used for instance used to normalize the paths provided
+ // with -I options. Like mcpp, we need to follow the symbolic
+ // links to ensure changeIncludes works correctly. For example, it
+ // must be possible to specify -I/opt/Ice-3.6 where Ice-3.6 is
+ // symbolic link to Ice-3.6.0 (if we don't do the same as mcpp,
+ // the generated headers will contain a full path...)
+ //
+
+ string result = path;
+ if(!IceUtilInternal::isAbsolutePath(result))
+ {
+ string cwd;
+ if(IceUtilInternal::getcwd(cwd) == 0)
+ {
+ result = string(cwd) + '/' + result;
+ }
+ }
+
+ result = normalizePath(result);
+
+#ifdef _WIN32
+ return result;
+#else
+
+ string::size_type beg = 0;
+ string::size_type next;
+ do
+ {
+ string subpath;
+ next = result.find('/', beg + 1);
+ if(next == string::npos)
+ {
+ subpath = result;
+ }
+ else
+ {
+ subpath = result.substr(0, next);
+ }
+
+ char buf[PATH_MAX + 1];
+ int len = static_cast<int>(readlink(subpath.c_str(), buf, sizeof(buf)));
+ if(len > 0)
+ {
+ buf[len] = '\0';
+ string linkpath = buf;
+ if(!IceUtilInternal::isAbsolutePath(linkpath)) // Path relative to the location of the link
+ {
+ string::size_type pos = subpath.rfind('/');
+ assert(pos != string::npos);
+ linkpath = subpath.substr(0, pos + 1) + linkpath;
+ }
+ result = normalizePath(linkpath) + (next != string::npos ? result.substr(next) : string());
+ beg = 0;
+ next = 0;
+ }
+ else
+ {
+ beg = next;
+ }
+ }
+ while(next != string::npos);
+ return result;
+#endif
+}
+
+string
+Slice::changeInclude(const string& p, const vector<string>& includePaths)
+{
+ string path = normalizePath(p);
+ //
+ // Compare each include path against the included file and select
+ // the path that produces the shortest relative filename.
+ //
+ string result = path;
+ vector<string> paths;
+ paths.push_back(path);
+ //
+ // if path is not a canonical path we also test with its canonical
+ // path
+ //
+ string canonicalPath = fullPath(path);
+ if(canonicalPath != path)
+ {
+ paths.push_back(canonicalPath);
+ }
+
+ for(vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i)
+ {
+ for(vector<string>::const_iterator j = includePaths.begin(); j != includePaths.end(); ++j)
+ {
+ if(i->compare(0, j->length(), *j) == 0)
+ {
+ string s = i->substr(j->length() + 1); // + 1 for the '/'
+ if(s.size() < result.size())
+ {
+ result = s;
+ }
+ }
+ }
+
+ //
+ // If the path has been already shortened no need to test
+ // with canonical path.
+ //
+ if(result != path)
+ {
+ break;
+ }
+ }
+
+ result = normalizePath(result); // Normalize the result.
+
+ string::size_type pos;
+ if((pos = result.rfind('.')) != string::npos)
+ {
+ result.erase(pos);
+ }
+
+ return result;
+}
+
+namespace
+{
+
+ostream* errorStream = &cerr;
+
+}
+
+void
+Slice::setErrorStream(ostream& stream)
+{
+ errorStream = &stream;
+}
+
+ostream&
+Slice::getErrorStream()
+{
+ return *errorStream;
+}
+
+void
+Slice::emitError(const string& file, int line, const string& message)
+{
+ if(!file.empty())
+ {
+ *errorStream << file;
+ if(line != -1)
+ {
+ *errorStream << ':' << line;
+ }
+ *errorStream << ": ";
+ }
+ *errorStream << message << endl;
+}
+
+void
+Slice::emitWarning(const string& file, int line, const string& message)
+{
+ if(!file.empty())
+ {
+ *errorStream << file;
+ if(line != -1)
+ {
+ *errorStream << ':' << line;
+ }
+ *errorStream << ": ";
+ }
+ *errorStream << "warning: " << message << endl;
+}
+
+void
+Slice::emitError(const string& file, const std::string& line, const string& message)
+{
+ if(!file.empty())
+ {
+ *errorStream << file;
+ if(!line.empty())
+ {
+ *errorStream << ':' << line;
+ }
+ *errorStream << ": ";
+ }
+ *errorStream << message << endl;
+}
+
+void
+Slice::emitWarning(const string& file, const std::string& line, const string& message)
+{
+ if(!file.empty())
+ {
+ *errorStream << file;
+ if(!line.empty())
+ {
+ *errorStream << ':' << line;
+ }
+ *errorStream << ": ";
+ }
+ *errorStream << "warning: " << message << endl;
+}
+
+void
+Slice::emitRaw(const char* message)
+{
+ *errorStream << message << flush;
+}
+
+vector<string>
+Slice::filterMcppWarnings(const string& message)
+{
+ static const char* messages[] =
+ {
+ "Converted [CR+LF] to [LF]",
+ "no newline, supplemented newline",
+ 0
+ };
+
+ static const string warningPrefix = "warning:";
+ static const string fromPrefix = "from";
+ static const string separators = "\n\t ";
+
+ vector<string> in;
+ string::size_type start = 0;
+ string::size_type end;
+ while((end = message.find('\n', start)) != string::npos)
+ {
+ in.push_back(message.substr(start, end - start));
+ start = end + 1;
+ }
+ vector<string> out;
+ bool skipped;
+ for(vector<string>::const_iterator i = in.begin(); i != in.end(); i++)
+ {
+ skipped = false;
+
+ if(i->find(warningPrefix) != string::npos)
+ {
+ for(int j = 0; messages[j] != 0; ++j)
+ {
+ if(i->find(messages[j]) != string::npos)
+ {
+ // This line should be skipped it contains the unwanted mcpp warning
+ // next line should also be skipped it contains the slice line that
+ // produces the skipped warning
+ i++;
+ skipped = true;
+ //
+ // Check if next lines are still the same warning
+ //
+ i++;
+ while(i != in.end())
+ {
+ string token = *i;
+ string::size_type index = token.find_first_not_of(separators);
+ if(index != string::npos)
+ {
+ token = token.substr(index);
+ }
+ if(token.find(fromPrefix) != 0)
+ {
+ //
+ // First line not of this warning
+ //
+ i--;
+ break;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ break;
+ }
+ }
+ if(i == in.end())
+ {
+ break;
+ }
+ }
+ if(!skipped)
+ {
+ out.push_back(*i + "\n");
+ }
+ }
+ return out;
+}
+
+void
+Slice::printGeneratedHeader(IceUtilInternal::Output& out, const string& path, const string& comment)
+{
+ //
+ // Get only the file name part of the given path.
+ //
+ string file = path;
+ size_t pos = file.find_last_of("/\\");
+ if(string::npos != pos)
+ {
+ file = file.substr(pos + 1);
+ }
+
+ out << comment << " <auto-generated>\n";
+ out << comment << "\n";
+ out << comment << " Generated from file `" << file << "'" << "\n";
+ out << comment << "\n";
+ out << comment << " Warning: do not edit this file." << "\n";
+ out << comment << "\n";
+ out << comment << " </auto-generated>\n";
+ out << comment << "\n";
+}
+
+Slice::DependOutputUtil::DependOutputUtil(string& file) : _file(file)
+{
+ if(!_file.empty())
+ {
+ _os.open(file.c_str(), ios::out);
+ }
+}
+
+Slice::DependOutputUtil::~DependOutputUtil()
+{
+ if(!_file.empty() && _os.is_open())
+ {
+ _os.close();
+ }
+}
+
+void
+Slice::DependOutputUtil::cleanup()
+{
+ if(!_file.empty())
+ {
+ if(_os.is_open())
+ {
+ _os.close();
+ }
+ IceUtilInternal::unlink(_file);
+ }
+}
+
+ostream&
+Slice::DependOutputUtil::os()
+{
+ return _file.empty() ? cout : _os;
+}