blob: 0548f621cb38088769dcd83333af1a33dd7825e5 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "strutil.h"
2
3#include <ctype.h>
4#include <string.h>
5
6#include <unordered_map>
7#include <utility>
8
9WordScanner::Iterator& WordScanner::Iterator::operator++() {
10 int len = static_cast<int>(in->size());
11 for (s = i; s < len; s++) {
12 if (!isspace((*in)[s]))
13 break;
14 }
15 if (s == len) {
16 in = NULL;
17 s = 0;
18 i = 0;
19 return *this;
20 }
21 for (i = s; i < len; i++) {
Shinichiro Hamaji63e68fc2015-06-16 17:36:53 +090022 if (isspace((*in)[i]))
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090023 break;
24 }
25 return *this;
26}
27
28StringPiece WordScanner::Iterator::operator*() const {
Shinichiro Hamaji63e68fc2015-06-16 17:36:53 +090029 return in->substr(s, i - s);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090030}
31
32WordScanner::WordScanner(StringPiece in)
33 : in_(in) {
34}
35
36WordScanner::Iterator WordScanner::begin() const {
37 Iterator iter;
38 iter.in = &in_;
39 iter.s = 0;
40 iter.i = 0;
41 ++iter;
42 return iter;
43}
44
45WordScanner::Iterator WordScanner::end() const {
46 Iterator iter;
47 iter.in = NULL;
48 iter.s = 0;
49 iter.i = 0;
50 return iter;
51}
52
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090053void WordScanner::Split(vector<StringPiece>* o) {
54 for (StringPiece t : *this)
55 o->push_back(t);
56}
57
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090058WordWriter::WordWriter(string* o)
59 : out_(o),
60 needs_space_(false) {
61}
62
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090063void WordWriter::MaybeAddWhitespace() {
Shinichiro Hamaji5e26e222015-06-16 19:38:47 +090064 if (needs_space_) {
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090065 out_->push_back(' ');
66 } else {
67 needs_space_ = true;
68 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090069}
70
71void WordWriter::Write(StringPiece s) {
72 MaybeAddWhitespace();
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090073 AppendString(s, out_);
74}
75
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090076static unordered_map<StringPiece, char*>* g_symtab;
77
78void InitSymtab() {
79 g_symtab = new unordered_map<StringPiece, char*>;
80}
81
82void QuitSymtab() {
83 for (auto p : *g_symtab) {
84 free(p.second);
85 }
86 delete g_symtab;
87}
88
89StringPiece Intern(StringPiece s) {
90 auto found = g_symtab->find(s);
91 if (found != g_symtab->end())
92 return found->first;
93
94 char* b = static_cast<char*>(malloc(s.size()+1));
95 memcpy(b, s.data(), s.size());
96 s = StringPiece(b, s.size());
97 (*g_symtab)[s] = b;
98 return s;
99}
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900100
101void AppendString(StringPiece str, string* out) {
102 out->append(str.begin(), str.end());
103}
104
105bool HasPrefix(StringPiece str, StringPiece prefix) {
106 ssize_t size_diff = str.size() - prefix.size();
Shinichiro Hamajif91d6822015-06-16 17:51:23 +0900107 return size_diff >= 0 && str.substr(0, prefix.size()) == prefix;
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900108}
109
110bool HasSuffix(StringPiece str, StringPiece suffix) {
111 ssize_t size_diff = str.size() - suffix.size();
112 return size_diff >= 0 && str.substr(size_diff) == suffix;
113}
114
115StringPiece TrimSuffix(StringPiece str, StringPiece suffix) {
116 ssize_t size_diff = str.size() - suffix.size();
117 if (size_diff < 0 || str.substr(size_diff) != suffix)
118 return str;
119 return str.substr(0, size_diff);
120}
121
122void AppendSubstPattern(StringPiece str, StringPiece pat, StringPiece subst,
123 string* out) {
124 size_t pat_percent_index = pat.find('%');
125 if (pat_percent_index == string::npos) {
126 if (str == pat) {
127 AppendString(subst, out);
128 return;
129 } else {
130 AppendString(str, out);
131 return;
132 }
133 }
134
135 if (HasPrefix(str, pat.substr(0, pat_percent_index)) &&
Shinichiro Hamajif91d6822015-06-16 17:51:23 +0900136 HasSuffix(str, pat.substr(pat_percent_index + 1))) {
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900137 size_t subst_percent_index = subst.find('%');
138 if (subst_percent_index == string::npos) {
139 AppendString(subst, out);
140 return;
141 } else {
142 AppendString(subst.substr(0, subst_percent_index), out);
143 AppendString(str.substr(pat_percent_index,
Shinichiro Hamajif91d6822015-06-16 17:51:23 +0900144 str.size() - pat.size() + 1), out);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900145 AppendString(subst.substr(subst_percent_index + 1), out);
146 return;
147 }
148 }
149 AppendString(str, out);
150}
151
152void AppendSubstRef(StringPiece str, StringPiece pat, StringPiece subst,
153 string* out) {
Shinichiro Hamajif91d6822015-06-16 17:51:23 +0900154 if (pat.find('%') != string::npos && subst.find('%') != string::npos) {
Shinichiro Hamajif019c3b2015-06-16 17:54:09 +0900155 AppendSubstPattern(str, pat, subst, out);
Shinichiro Hamajif91d6822015-06-16 17:51:23 +0900156 return;
157 }
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900158 StringPiece s = TrimSuffix(str, pat);
159 out->append(s.begin(), s.end());
160 out->append(subst.begin(), subst.end());
161}
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900162
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900163bool MatchPattern(StringPiece str, StringPiece pat) {
164 size_t i = pat.find('%');
165 if (i == string::npos)
166 return str == pat;
167 return HasPrefix(str, pat.substr(0, i)) && HasSuffix(str, pat.substr(i+1));
168}
169
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900170string NoLineBreak(const string& s) {
171 size_t index = s.find('\n');
172 if (index == string::npos)
173 return s;
174 string r = s;
175 while (index != string::npos) {
176 r = s.substr(0, index) + "\\n" + s.substr(index + 1);
177 index = s.find('\n', index + 2);
178 }
179 return r;
180}
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900181
182StringPiece TrimLeftSpace(StringPiece s) {
183 size_t i = 0;
184 while (i < s.size() && isspace(s[i]))
185 i++;
186 return s.substr(i, s.size() - i);
187}
188
189StringPiece TrimRightSpace(StringPiece s) {
190 size_t i = 0;
191 while (i < s.size() && isspace(s[s.size() - 1 - i]))
192 i++;
193 return s.substr(0, s.size() - i);
194}
195
196StringPiece TrimSpace(StringPiece s) {
197 return TrimRightSpace(TrimLeftSpace(s));
198}
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900199
200StringPiece Dirname(StringPiece s) {
201 size_t found = s.rfind('/');
202 if (found == string::npos)
203 return STRING_PIECE(".");
204 if (found == 0)
205 return s;
206 return s.substr(0, found);
207}
208
209StringPiece Basename(StringPiece s) {
210 size_t found = s.rfind('/');
211 if (found == string::npos || found == 0)
212 return s;
213 return s.substr(found + 1);
214}
215
216StringPiece GetExt(StringPiece s) {
217 size_t found = s.rfind('.');
218 if (found == string::npos)
219 return STRING_PIECE("");
220 return s.substr(found);
221}
222
223StringPiece StripExt(StringPiece s) {
224 size_t slash_index = s.rfind('/');
225 size_t found = s.rfind('.');
226 if (found == string::npos ||
227 (slash_index != string::npos && found < slash_index))
228 return s;
229 return s.substr(0, found);
230}