strutil.cc revision 32750621508da5e68f53bf14f944ad524627eb50
1#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++) {
22    if (isspace((*in)[i]))
23      break;
24  }
25  return *this;
26}
27
28StringPiece WordScanner::Iterator::operator*() const {
29  return in->substr(s, i - s);
30}
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
53WordWriter::WordWriter(string* o)
54    : out_(o),
55      needs_space_(false) {
56}
57
58void WordWriter::MaybeAddWhitespace() {
59  if (needs_space_) {
60    out_->push_back(' ');
61  } else {
62    needs_space_ = true;
63  }
64}
65
66void WordWriter::Write(StringPiece s) {
67  MaybeAddWhitespace();
68  AppendString(s, out_);
69}
70
71static unordered_map<StringPiece, char*>* g_symtab;
72
73void InitSymtab() {
74  g_symtab = new unordered_map<StringPiece, char*>;
75}
76
77void QuitSymtab() {
78  for (auto p : *g_symtab) {
79    free(p.second);
80  }
81  delete g_symtab;
82}
83
84StringPiece Intern(StringPiece s) {
85  auto found = g_symtab->find(s);
86  if (found != g_symtab->end())
87    return found->first;
88
89  char* b = static_cast<char*>(malloc(s.size()+1));
90  memcpy(b, s.data(), s.size());
91  s = StringPiece(b, s.size());
92  (*g_symtab)[s] = b;
93  return s;
94}
95
96void AppendString(StringPiece str, string* out) {
97  out->append(str.begin(), str.end());
98}
99
100bool HasPrefix(StringPiece str, StringPiece prefix) {
101  ssize_t size_diff = str.size() - prefix.size();
102  return size_diff >= 0 && str.substr(0, prefix.size()) == prefix;
103}
104
105bool HasSuffix(StringPiece str, StringPiece suffix) {
106  ssize_t size_diff = str.size() - suffix.size();
107  return size_diff >= 0 && str.substr(size_diff) == suffix;
108}
109
110StringPiece TrimSuffix(StringPiece str, StringPiece suffix) {
111  ssize_t size_diff = str.size() - suffix.size();
112  if (size_diff < 0 || str.substr(size_diff) != suffix)
113    return str;
114  return str.substr(0, size_diff);
115}
116
117void AppendSubstPattern(StringPiece str, StringPiece pat, StringPiece subst,
118                        string* out) {
119  size_t pat_percent_index = pat.find('%');
120  if (pat_percent_index == string::npos) {
121    if (str == pat) {
122      AppendString(subst, out);
123      return;
124    } else {
125      AppendString(str, out);
126      return;
127    }
128  }
129
130  if (HasPrefix(str, pat.substr(0, pat_percent_index)) &&
131      HasSuffix(str, pat.substr(pat_percent_index + 1))) {
132    size_t subst_percent_index = subst.find('%');
133    if (subst_percent_index == string::npos) {
134      AppendString(subst, out);
135      return;
136    } else {
137      AppendString(subst.substr(0, subst_percent_index), out);
138      AppendString(str.substr(pat_percent_index,
139                              str.size() - pat.size() + 1), out);
140      AppendString(subst.substr(subst_percent_index + 1), out);
141      return;
142    }
143  }
144  AppendString(str, out);
145}
146
147void AppendSubstRef(StringPiece str, StringPiece pat, StringPiece subst,
148                    string* out) {
149  if (pat.find('%') != string::npos && subst.find('%') != string::npos) {
150    AppendSubstPattern(str, pat, subst, out);
151    return;
152  }
153  StringPiece s = TrimSuffix(str, pat);
154  out->append(s.begin(), s.end());
155  out->append(subst.begin(), subst.end());
156}
157
158string NoLineBreak(const string& s) {
159  size_t index = s.find('\n');
160  if (index == string::npos)
161    return s;
162  string r = s;
163  while (index != string::npos) {
164    r = s.substr(0, index) + "\\n" + s.substr(index + 1);
165    index = s.find('\n', index + 2);
166  }
167  return r;
168}
169
170StringPiece TrimLeftSpace(StringPiece s) {
171  size_t i = 0;
172  while (i < s.size() && isspace(s[i]))
173    i++;
174  return s.substr(i, s.size() - i);
175}
176
177StringPiece TrimRightSpace(StringPiece s) {
178  size_t i = 0;
179  while (i < s.size() && isspace(s[s.size() - 1 - i]))
180    i++;
181  return s.substr(0, s.size() - i);
182}
183
184StringPiece TrimSpace(StringPiece s) {
185  return TrimRightSpace(TrimLeftSpace(s));
186}
187