Shinichiro Hamaji | 776ca30 | 2015-06-06 03:52:48 +0900 | [diff] [blame] | 1 | #include "strutil.h" |
| 2 | |
| 3 | #include <ctype.h> |
| 4 | #include <string.h> |
| 5 | |
| 6 | #include <unordered_map> |
| 7 | #include <utility> |
| 8 | |
| 9 | WordScanner::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 Hamaji | 63e68fc | 2015-06-16 17:36:53 +0900 | [diff] [blame] | 22 | if (isspace((*in)[i])) |
Shinichiro Hamaji | 776ca30 | 2015-06-06 03:52:48 +0900 | [diff] [blame] | 23 | break; |
| 24 | } |
| 25 | return *this; |
| 26 | } |
| 27 | |
| 28 | StringPiece WordScanner::Iterator::operator*() const { |
Shinichiro Hamaji | 63e68fc | 2015-06-16 17:36:53 +0900 | [diff] [blame] | 29 | return in->substr(s, i - s); |
Shinichiro Hamaji | 776ca30 | 2015-06-06 03:52:48 +0900 | [diff] [blame] | 30 | } |
| 31 | |
| 32 | WordScanner::WordScanner(StringPiece in) |
| 33 | : in_(in) { |
| 34 | } |
| 35 | |
| 36 | WordScanner::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 | |
| 45 | WordScanner::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 Hamaji | d87e59e | 2015-06-17 18:18:34 +0900 | [diff] [blame] | 53 | void WordScanner::Split(vector<StringPiece>* o) { |
| 54 | for (StringPiece t : *this) |
| 55 | o->push_back(t); |
| 56 | } |
| 57 | |
Shinichiro Hamaji | 2e6cbfc | 2015-06-16 18:46:50 +0900 | [diff] [blame] | 58 | WordWriter::WordWriter(string* o) |
| 59 | : out_(o), |
| 60 | needs_space_(false) { |
| 61 | } |
| 62 | |
Shinichiro Hamaji | 37591ce | 2015-06-16 19:36:05 +0900 | [diff] [blame] | 63 | void WordWriter::MaybeAddWhitespace() { |
Shinichiro Hamaji | 5e26e22 | 2015-06-16 19:38:47 +0900 | [diff] [blame] | 64 | if (needs_space_) { |
Shinichiro Hamaji | 2e6cbfc | 2015-06-16 18:46:50 +0900 | [diff] [blame] | 65 | out_->push_back(' '); |
| 66 | } else { |
| 67 | needs_space_ = true; |
| 68 | } |
Shinichiro Hamaji | 37591ce | 2015-06-16 19:36:05 +0900 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | void WordWriter::Write(StringPiece s) { |
| 72 | MaybeAddWhitespace(); |
Shinichiro Hamaji | 2e6cbfc | 2015-06-16 18:46:50 +0900 | [diff] [blame] | 73 | AppendString(s, out_); |
| 74 | } |
| 75 | |
Shinichiro Hamaji | 776ca30 | 2015-06-06 03:52:48 +0900 | [diff] [blame] | 76 | static unordered_map<StringPiece, char*>* g_symtab; |
| 77 | |
| 78 | void InitSymtab() { |
| 79 | g_symtab = new unordered_map<StringPiece, char*>; |
| 80 | } |
| 81 | |
| 82 | void QuitSymtab() { |
| 83 | for (auto p : *g_symtab) { |
| 84 | free(p.second); |
| 85 | } |
| 86 | delete g_symtab; |
| 87 | } |
| 88 | |
| 89 | StringPiece 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 Hamaji | 02fc55b | 2015-06-16 17:19:07 +0900 | [diff] [blame] | 100 | |
| 101 | void AppendString(StringPiece str, string* out) { |
| 102 | out->append(str.begin(), str.end()); |
| 103 | } |
| 104 | |
| 105 | bool HasPrefix(StringPiece str, StringPiece prefix) { |
| 106 | ssize_t size_diff = str.size() - prefix.size(); |
Shinichiro Hamaji | f91d682 | 2015-06-16 17:51:23 +0900 | [diff] [blame] | 107 | return size_diff >= 0 && str.substr(0, prefix.size()) == prefix; |
Shinichiro Hamaji | 02fc55b | 2015-06-16 17:19:07 +0900 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | bool 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 | |
| 115 | StringPiece 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 | |
| 122 | void 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 Hamaji | f91d682 | 2015-06-16 17:51:23 +0900 | [diff] [blame] | 136 | HasSuffix(str, pat.substr(pat_percent_index + 1))) { |
Shinichiro Hamaji | 02fc55b | 2015-06-16 17:19:07 +0900 | [diff] [blame] | 137 | 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 Hamaji | f91d682 | 2015-06-16 17:51:23 +0900 | [diff] [blame] | 144 | str.size() - pat.size() + 1), out); |
Shinichiro Hamaji | 02fc55b | 2015-06-16 17:19:07 +0900 | [diff] [blame] | 145 | AppendString(subst.substr(subst_percent_index + 1), out); |
| 146 | return; |
| 147 | } |
| 148 | } |
| 149 | AppendString(str, out); |
| 150 | } |
| 151 | |
| 152 | void AppendSubstRef(StringPiece str, StringPiece pat, StringPiece subst, |
| 153 | string* out) { |
Shinichiro Hamaji | f91d682 | 2015-06-16 17:51:23 +0900 | [diff] [blame] | 154 | if (pat.find('%') != string::npos && subst.find('%') != string::npos) { |
Shinichiro Hamaji | f019c3b | 2015-06-16 17:54:09 +0900 | [diff] [blame] | 155 | AppendSubstPattern(str, pat, subst, out); |
Shinichiro Hamaji | f91d682 | 2015-06-16 17:51:23 +0900 | [diff] [blame] | 156 | return; |
| 157 | } |
Shinichiro Hamaji | 02fc55b | 2015-06-16 17:19:07 +0900 | [diff] [blame] | 158 | StringPiece s = TrimSuffix(str, pat); |
| 159 | out->append(s.begin(), s.end()); |
| 160 | out->append(subst.begin(), subst.end()); |
| 161 | } |
Shinichiro Hamaji | 810fd03 | 2015-06-17 04:38:03 +0900 | [diff] [blame] | 162 | |
Shinichiro Hamaji | 00cc658 | 2015-06-17 18:12:46 +0900 | [diff] [blame] | 163 | bool 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 Hamaji | 810fd03 | 2015-06-17 04:38:03 +0900 | [diff] [blame] | 170 | string 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 Hamaji | 3275062 | 2015-06-17 14:57:33 +0900 | [diff] [blame] | 181 | |
| 182 | StringPiece 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 | |
| 189 | StringPiece 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 | |
| 196 | StringPiece TrimSpace(StringPiece s) { |
| 197 | return TrimRightSpace(TrimLeftSpace(s)); |
| 198 | } |
Shinichiro Hamaji | 67f9a70 | 2015-06-18 06:00:57 +0900 | [diff] [blame^] | 199 | |
| 200 | StringPiece 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 | |
| 209 | StringPiece 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 | |
| 216 | StringPiece 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 | |
| 223 | StringPiece 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 | } |