1*11be35a1SLionel Sambuc // Copyright 2012 Google Inc.
2*11be35a1SLionel Sambuc // All rights reserved.
3*11be35a1SLionel Sambuc //
4*11be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
5*11be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
6*11be35a1SLionel Sambuc // met:
7*11be35a1SLionel Sambuc //
8*11be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
9*11be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer.
10*11be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
11*11be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer in the
12*11be35a1SLionel Sambuc // documentation and/or other materials provided with the distribution.
13*11be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
14*11be35a1SLionel Sambuc // may be used to endorse or promote products derived from this software
15*11be35a1SLionel Sambuc // without specific prior written permission.
16*11be35a1SLionel Sambuc //
17*11be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*11be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*11be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*11be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*11be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*11be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*11be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*11be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*11be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*11be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*11be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc
29*11be35a1SLionel Sambuc #include "utils/text/operations.ipp"
30*11be35a1SLionel Sambuc
31*11be35a1SLionel Sambuc #include <sstream>
32*11be35a1SLionel Sambuc
33*11be35a1SLionel Sambuc #include "utils/format/macros.hpp"
34*11be35a1SLionel Sambuc #include "utils/sanity.hpp"
35*11be35a1SLionel Sambuc
36*11be35a1SLionel Sambuc namespace text = utils::text;
37*11be35a1SLionel Sambuc
38*11be35a1SLionel Sambuc
39*11be35a1SLionel Sambuc /// Surrounds a string with quotes, escaping the quote itself if needed.
40*11be35a1SLionel Sambuc ///
41*11be35a1SLionel Sambuc /// \param text The string to quote.
42*11be35a1SLionel Sambuc /// \param quote The quote character to use.
43*11be35a1SLionel Sambuc ///
44*11be35a1SLionel Sambuc /// \return The quoted string.
45*11be35a1SLionel Sambuc std::string
quote(const std::string & text,const char quote)46*11be35a1SLionel Sambuc text::quote(const std::string& text, const char quote)
47*11be35a1SLionel Sambuc {
48*11be35a1SLionel Sambuc std::ostringstream quoted;
49*11be35a1SLionel Sambuc quoted << quote;
50*11be35a1SLionel Sambuc
51*11be35a1SLionel Sambuc std::string::size_type start_pos = 0;
52*11be35a1SLionel Sambuc std::string::size_type last_pos = text.find(quote);
53*11be35a1SLionel Sambuc while (last_pos != std::string::npos) {
54*11be35a1SLionel Sambuc quoted << text.substr(start_pos, last_pos - start_pos) << '\\';
55*11be35a1SLionel Sambuc start_pos = last_pos;
56*11be35a1SLionel Sambuc last_pos = text.find(quote, start_pos + 1);
57*11be35a1SLionel Sambuc }
58*11be35a1SLionel Sambuc quoted << text.substr(start_pos);
59*11be35a1SLionel Sambuc
60*11be35a1SLionel Sambuc quoted << quote;
61*11be35a1SLionel Sambuc return quoted.str();
62*11be35a1SLionel Sambuc }
63*11be35a1SLionel Sambuc
64*11be35a1SLionel Sambuc
65*11be35a1SLionel Sambuc /// Fills a paragraph to the specified length.
66*11be35a1SLionel Sambuc ///
67*11be35a1SLionel Sambuc /// This preserves any sequence of spaces in the input and any possible
68*11be35a1SLionel Sambuc /// newlines. Sequences of spaces may be split in half (and thus one space is
69*11be35a1SLionel Sambuc /// lost), but the rest of the spaces will be preserved as either trailing or
70*11be35a1SLionel Sambuc /// leading spaces.
71*11be35a1SLionel Sambuc ///
72*11be35a1SLionel Sambuc /// \param input The string to refill.
73*11be35a1SLionel Sambuc /// \param target_width The width to refill the paragraph to.
74*11be35a1SLionel Sambuc ///
75*11be35a1SLionel Sambuc /// \return The refilled paragraph as a sequence of independent lines.
76*11be35a1SLionel Sambuc std::vector< std::string >
refill(const std::string & input,const std::size_t target_width)77*11be35a1SLionel Sambuc text::refill(const std::string& input, const std::size_t target_width)
78*11be35a1SLionel Sambuc {
79*11be35a1SLionel Sambuc std::vector< std::string > output;
80*11be35a1SLionel Sambuc
81*11be35a1SLionel Sambuc std::string::size_type start = 0;
82*11be35a1SLionel Sambuc while (start < input.length()) {
83*11be35a1SLionel Sambuc std::string::size_type width;
84*11be35a1SLionel Sambuc if (start + target_width >= input.length())
85*11be35a1SLionel Sambuc width = input.length() - start;
86*11be35a1SLionel Sambuc else {
87*11be35a1SLionel Sambuc if (input[start + target_width] == ' ') {
88*11be35a1SLionel Sambuc width = target_width;
89*11be35a1SLionel Sambuc } else {
90*11be35a1SLionel Sambuc const std::string::size_type pos = input.find_last_of(
91*11be35a1SLionel Sambuc " ", start + target_width - 1);
92*11be35a1SLionel Sambuc if (pos == std::string::npos || pos < start + 1) {
93*11be35a1SLionel Sambuc width = input.find_first_of(" ", start + target_width);
94*11be35a1SLionel Sambuc if (width == std::string::npos)
95*11be35a1SLionel Sambuc width = input.length() - start;
96*11be35a1SLionel Sambuc else
97*11be35a1SLionel Sambuc width -= start;
98*11be35a1SLionel Sambuc } else {
99*11be35a1SLionel Sambuc width = pos - start;
100*11be35a1SLionel Sambuc }
101*11be35a1SLionel Sambuc }
102*11be35a1SLionel Sambuc }
103*11be35a1SLionel Sambuc INV(width != std::string::npos);
104*11be35a1SLionel Sambuc INV(start + width <= input.length());
105*11be35a1SLionel Sambuc INV(input[start + width] == ' ' || input[start + width] == '\0');
106*11be35a1SLionel Sambuc output.push_back(input.substr(start, width));
107*11be35a1SLionel Sambuc
108*11be35a1SLionel Sambuc start += width + 1;
109*11be35a1SLionel Sambuc }
110*11be35a1SLionel Sambuc
111*11be35a1SLionel Sambuc if (input.empty()) {
112*11be35a1SLionel Sambuc INV(output.empty());
113*11be35a1SLionel Sambuc output.push_back("");
114*11be35a1SLionel Sambuc }
115*11be35a1SLionel Sambuc
116*11be35a1SLionel Sambuc return output;
117*11be35a1SLionel Sambuc }
118*11be35a1SLionel Sambuc
119*11be35a1SLionel Sambuc
120*11be35a1SLionel Sambuc /// Fills a paragraph to the specified length.
121*11be35a1SLionel Sambuc ///
122*11be35a1SLionel Sambuc /// See the documentation for refill() for additional details.
123*11be35a1SLionel Sambuc ///
124*11be35a1SLionel Sambuc /// \param input The string to refill.
125*11be35a1SLionel Sambuc /// \param target_width The width to refill the paragraph to.
126*11be35a1SLionel Sambuc ///
127*11be35a1SLionel Sambuc /// \return The refilled paragraph as a string with embedded newlines.
128*11be35a1SLionel Sambuc std::string
refill_as_string(const std::string & input,const std::size_t target_width)129*11be35a1SLionel Sambuc text::refill_as_string(const std::string& input, const std::size_t target_width)
130*11be35a1SLionel Sambuc {
131*11be35a1SLionel Sambuc return join(refill(input, target_width), "\n");
132*11be35a1SLionel Sambuc }
133*11be35a1SLionel Sambuc
134*11be35a1SLionel Sambuc
135*11be35a1SLionel Sambuc /// Splits a string into different components.
136*11be35a1SLionel Sambuc ///
137*11be35a1SLionel Sambuc /// \param str The string to split.
138*11be35a1SLionel Sambuc /// \param delimiter The separator to use to split the words.
139*11be35a1SLionel Sambuc ///
140*11be35a1SLionel Sambuc /// \return The different words in the input string as split by the provided
141*11be35a1SLionel Sambuc /// delimiter.
142*11be35a1SLionel Sambuc std::vector< std::string >
split(const std::string & str,const char delimiter)143*11be35a1SLionel Sambuc text::split(const std::string& str, const char delimiter)
144*11be35a1SLionel Sambuc {
145*11be35a1SLionel Sambuc std::vector< std::string > words;
146*11be35a1SLionel Sambuc if (!str.empty()) {
147*11be35a1SLionel Sambuc std::string::size_type pos = str.find(delimiter);
148*11be35a1SLionel Sambuc words.push_back(str.substr(0, pos));
149*11be35a1SLionel Sambuc while (pos != std::string::npos) {
150*11be35a1SLionel Sambuc ++pos;
151*11be35a1SLionel Sambuc const std::string::size_type next = str.find(delimiter, pos);
152*11be35a1SLionel Sambuc words.push_back(str.substr(pos, next - pos));
153*11be35a1SLionel Sambuc pos = next;
154*11be35a1SLionel Sambuc }
155*11be35a1SLionel Sambuc }
156*11be35a1SLionel Sambuc return words;
157*11be35a1SLionel Sambuc }
158*11be35a1SLionel Sambuc
159*11be35a1SLionel Sambuc
160*11be35a1SLionel Sambuc /// Converts a string to a boolean.
161*11be35a1SLionel Sambuc ///
162*11be35a1SLionel Sambuc /// \param str The string to convert.
163*11be35a1SLionel Sambuc ///
164*11be35a1SLionel Sambuc /// \return The converted string, if the input string was valid.
165*11be35a1SLionel Sambuc ///
166*11be35a1SLionel Sambuc /// \throw std::value_error If the input string does not represent a valid
167*11be35a1SLionel Sambuc /// boolean value.
168*11be35a1SLionel Sambuc template<>
169*11be35a1SLionel Sambuc bool
to_type(const std::string & str)170*11be35a1SLionel Sambuc text::to_type(const std::string& str)
171*11be35a1SLionel Sambuc {
172*11be35a1SLionel Sambuc if (str == "true")
173*11be35a1SLionel Sambuc return true;
174*11be35a1SLionel Sambuc else if (str == "false")
175*11be35a1SLionel Sambuc return false;
176*11be35a1SLionel Sambuc else
177*11be35a1SLionel Sambuc throw value_error(F("Invalid boolean value '%s'") % str);
178*11be35a1SLionel Sambuc }
179*11be35a1SLionel Sambuc
180*11be35a1SLionel Sambuc
181*11be35a1SLionel Sambuc /// Identity function for to_type, for genericity purposes.
182*11be35a1SLionel Sambuc ///
183*11be35a1SLionel Sambuc /// \param str The string to convert.
184*11be35a1SLionel Sambuc ///
185*11be35a1SLionel Sambuc /// \return The input string.
186*11be35a1SLionel Sambuc template<>
187*11be35a1SLionel Sambuc std::string
to_type(const std::string & str)188*11be35a1SLionel Sambuc text::to_type(const std::string& str)
189*11be35a1SLionel Sambuc {
190*11be35a1SLionel Sambuc return str;
191*11be35a1SLionel Sambuc }
192