blob: f6b9a35243ee0eaa1e19ee8267fb3fa3d2ea6775 [file] [log] [blame]
Andreas Huber84f89de2016-07-28 15:39:51 -07001#include "FQName.h"
2
3#include <android-base/logging.h>
4#include <regex>
5
6#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
7#define RE_PATH RE_COMPONENT "([.]" RE_COMPONENT ")*"
8#define RE_VERSION "@[0-9]+[.][0-9]+"
9
10static const std::regex kRE1("(" RE_PATH ")(" RE_VERSION ")?::(" RE_PATH ")");
11static const std::regex kRE2("(" RE_VERSION ")::(" RE_PATH ")");
Andreas Huberda51b8e2016-07-28 16:00:57 -070012static const std::regex kRE3("(" RE_PATH ")(" RE_VERSION ")");
13static const std::regex kRE4(RE_PATH);
Andreas Huber84f89de2016-07-28 15:39:51 -070014
15namespace android {
16
Andreas Huberda51b8e2016-07-28 16:00:57 -070017FQName::FQName()
18 : mValid(false) {
19}
20
Andreas Huber84f89de2016-07-28 15:39:51 -070021FQName::FQName(const std::string &s)
22 : mValid(false) {
23 setTo(s);
24}
25
Andreas Huber68f24592016-07-29 14:53:48 -070026FQName::FQName(
27 const std::string &package,
28 const std::string &version,
29 const std::string &name)
30 : mValid(true),
31 mPackage(package),
32 mVersion(version),
33 mName(name) {
34}
35
Andreas Huber84f89de2016-07-28 15:39:51 -070036bool FQName::isValid() const {
37 return mValid;
38}
39
Andreas Huber68f24592016-07-29 14:53:48 -070040bool FQName::isFullyQualified() const {
41 return !mPackage.empty() && !mVersion.empty() && !mName.empty();
42}
43
Andreas Huber84f89de2016-07-28 15:39:51 -070044bool FQName::setTo(const std::string &s) {
45 mPackage.clear();
46 mVersion.clear();
47 mName.clear();
48
49 mValid = true;
50
51 std::smatch match;
52 if (std::regex_match(s, match, kRE1)) {
53 CHECK_EQ(match.size(), 6u);
54
55 mPackage = match.str(1);
56 mVersion = match.str(3);
57 mName = match.str(4);
58 } else if (std::regex_match(s, match, kRE2)) {
59 CHECK_EQ(match.size(), 4u);
60
61 mVersion = match.str(1);
62 mName = match.str(2);
63 } else if (std::regex_match(s, match, kRE3)) {
Andreas Huberda51b8e2016-07-28 16:00:57 -070064 CHECK_EQ(match.size(), 4u);
65
66 mPackage = match.str(1);
67 mVersion = match.str(3);
68 } else if (std::regex_match(s, match, kRE4)) {
Andreas Huber84f89de2016-07-28 15:39:51 -070069 mName = match.str(0);
70 } else {
71 mValid = false;
72 }
73
74 return isValid();
75}
76
77std::string FQName::package() const {
78 return mPackage;
79}
80
81std::string FQName::version() const {
82 return mVersion;
83}
84
85std::string FQName::name() const {
86 return mName;
87}
88
89void FQName::applyDefaults(
90 const std::string &defaultPackage,
91 const std::string &defaultVersion) {
92 if (mPackage.empty()) {
93 mPackage = defaultPackage;
94 }
95
96 if (mVersion.empty()) {
97 mVersion = defaultVersion;
98 }
99}
100
Andreas Huber68f24592016-07-29 14:53:48 -0700101std::string FQName::string() const {
Andreas Huber84f89de2016-07-28 15:39:51 -0700102 CHECK(mValid);
103
Andreas Huber5345ec22016-07-29 13:33:27 -0700104 std::string out;
Andreas Huber84f89de2016-07-28 15:39:51 -0700105 out.append(mPackage);
106 out.append(mVersion);
Andreas Huberda51b8e2016-07-28 16:00:57 -0700107 if (!mName.empty()) {
108 if (!mPackage.empty() || !mVersion.empty()) {
109 out.append("::");
110 }
111 out.append(mName);
Andreas Huber84f89de2016-07-28 15:39:51 -0700112 }
Andreas Huber84f89de2016-07-28 15:39:51 -0700113
114 return out;
115}
116
Andreas Huberda51b8e2016-07-28 16:00:57 -0700117void FQName::print() const {
118 if (!mValid) {
119 LOG(INFO) << "INVALID";
120 return;
121 }
122
Andreas Huber68f24592016-07-29 14:53:48 -0700123 LOG(INFO) << string();
124}
125
126bool FQName::operator<(const FQName &other) const {
127 return string() < other.string();
Andreas Huberda51b8e2016-07-28 16:00:57 -0700128}
129
Andreas Huber0e00de42016-08-03 09:56:02 -0700130static void SplitString(
131 const std::string &s, char c, std::vector<std::string> *components) {
132 components->clear();
133
134 size_t startPos = 0;
135 size_t matchPos;
136 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
137 components->push_back(s.substr(startPos, matchPos - startPos));
138 startPos = matchPos + 1;
139 }
140
141 if (startPos + 1 < s.length()) {
142 components->push_back(s.substr(startPos));
143 }
144}
145
146static std::string JoinStrings(
147 const std::vector<std::string> &components,
148 const std::string &separator) {
149 std::string out;
150 bool first = true;
151 for (const auto &component : components) {
152 if (!first) {
153 out += separator;
154 }
155 out += component;
156
157 first = false;
158 }
159
160 return out;
161}
162
163std::string FQName::cppNamespace() const {
164 std::vector<std::string> components;
165 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
166
167 std::string out = "::";
168 out += JoinStrings(components, "::");
169
170 return out;
171}
172
173std::string FQName::cppName() const {
174 std::string out = cppNamespace();
175
176 std::vector<std::string> components;
177 SplitString(name(), '.', &components);
178 out += "::";
179 out += JoinStrings(components, "::");
180
181 return out;
182}
183
184void FQName::getPackageComponents(std::vector<std::string> *components) const {
185 SplitString(package(), '.', components);
186}
187
188void FQName::getPackageAndVersionComponents(
189 std::vector<std::string> *components,
190 bool cpp_compatible) const {
191 getPackageComponents(components);
192
193 const std::string packageVersion = version();
194 CHECK(packageVersion[0] == '@');
195
196 if (!cpp_compatible) {
197 components->push_back(packageVersion.substr(1));
198 return;
199 }
200
201 const size_t dotPos = packageVersion.find('.');
202
203 // Form "Vmajor_minor".
204 std::string versionString = "V";
205 versionString.append(packageVersion.substr(1, dotPos - 1));
206 versionString.append("_");
207 versionString.append(packageVersion.substr(dotPos + 1));
208
209 components->push_back(versionString);
210}
211
Andreas Huber84f89de2016-07-28 15:39:51 -0700212} // namespace android
213