Line data Source code
1 : //
2 : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/url
8 : //
9 :
10 : #ifndef BOOST_URL_DETAIL_IMPL_PCT_FORMAT_IPP
11 : #define BOOST_URL_DETAIL_IMPL_PCT_FORMAT_IPP
12 :
13 : #include <boost/url/detail/config.hpp>
14 : #include <boost/url/detail/pct_format.hpp>
15 : #include <boost/url/grammar/parse.hpp>
16 : #include <boost/url/grammar/unsigned_rule.hpp>
17 :
18 : namespace boost {
19 : namespace urls {
20 : namespace detail {
21 :
22 : std::size_t
23 250 : pct_vmeasure(
24 : grammar::lut_chars const& cs,
25 : format_parse_context& pctx,
26 : measure_context& mctx)
27 : {
28 250 : auto it0 = pctx.begin();
29 250 : auto end = pctx.end();
30 488 : while( it0 != end )
31 : {
32 : // look for replacement id
33 295 : char const* it1 = it0;
34 467 : while(
35 762 : it1 != end &&
36 707 : *it1 != '{' )
37 : {
38 467 : ++it1;
39 : }
40 :
41 : // output literal prefix
42 295 : if( it0 != it1 )
43 : {
44 584 : for (char const* i = it0; i != it1; ++i)
45 467 : mctx.advance_to( mctx.out() + measure_one(*i, cs));
46 : }
47 :
48 : // over
49 295 : if( it1 == end )
50 : {
51 55 : break;
52 : }
53 :
54 : // enter replacement id
55 240 : ++it1;
56 240 : BOOST_ASSERT(it1 != end);
57 :
58 : // handle escaped replacement (second '{')
59 : // there's no "{{" in URL templates because
60 : // '{'s are not allowed in URLs
61 240 : BOOST_ASSERT(*it1 != '{');
62 : /*
63 : if( *it1 == '{' )
64 : {
65 : mctx.advance_to( mctx.out() + measure_one('{', cs));
66 : ++it1;
67 : // this was not a real replacement,
68 : // so we just keep moving
69 : continue;
70 : }
71 : */
72 :
73 :
74 : // parse {id} or {id:specs}
75 240 : char const* id_start = it1;
76 570 : while (it1 != end &&
77 405 : *it1 != ':' &&
78 364 : *it1 != '}')
79 : {
80 165 : ++it1;
81 : }
82 240 : core::string_view id(id_start, it1);
83 :
84 : // move to specs start
85 240 : if (it1 != end &&
86 240 : *it1 == ':')
87 41 : ++it1;
88 240 : pctx.advance_to( it1 );
89 :
90 : // get format_arg to use
91 : auto idv = grammar::parse(
92 240 : id, grammar::unsigned_rule<std::size_t>{});
93 240 : if (idv)
94 : {
95 27 : mctx.arg( *idv ).measure( pctx, mctx, cs );
96 : }
97 213 : else if (!id.empty())
98 : {
99 26 : mctx.arg( id ).measure( pctx, mctx, cs );
100 : }
101 : else
102 : {
103 187 : std::size_t arg_id = pctx.next_arg_id();
104 187 : mctx.arg( arg_id ).measure( pctx, mctx, cs );
105 : }
106 :
107 :
108 238 : it1 = pctx.begin();
109 238 : BOOST_ASSERT(*it1 == '}');
110 238 : it0 = it1 + 1;
111 : }
112 :
113 248 : return mctx.out();
114 : }
115 :
116 : char*
117 245 : pct_vformat(
118 : grammar::lut_chars const& cs,
119 : format_parse_context& pctx,
120 : format_context& fctx)
121 : {
122 245 : auto it0 = pctx.begin();
123 245 : auto end = pctx.end();
124 481 : while( it0 != end )
125 : {
126 : // look for replacement id
127 290 : char const* it1 = it0;
128 458 : while(
129 748 : it1 != end &&
130 694 : *it1 != '{' )
131 : {
132 458 : ++it1;
133 : }
134 :
135 : // output literal prefix
136 290 : if( it0 != it1 )
137 : {
138 574 : for (char const* i = it0; i != it1; ++i)
139 : {
140 458 : char* o = fctx.out();
141 458 : encode_one(o, *i, cs);
142 458 : fctx.advance_to(o);
143 : }
144 : }
145 :
146 : // over
147 290 : if( it1 == end )
148 : {
149 54 : break;
150 : }
151 :
152 : // enter replacement id
153 236 : ++it1;
154 236 : BOOST_ASSERT(it1 != end);
155 :
156 : // handle escaped replacement (second '{')
157 : // there's no "{{" in URL templates because
158 : // '{'s are not allowed in URLs
159 236 : BOOST_ASSERT(*it1 != '{');
160 : /*
161 : if( *it1 == '{' )
162 : {
163 : char* o = fctx.out();
164 : encode_one(o, '{', cs);
165 : fctx.advance_to(o);
166 : ++it1;
167 : // this was not a real replacement,
168 : // so we just keep moving
169 : continue;
170 : }
171 : */
172 :
173 : // parse {id} or {id:specs}
174 236 : char const* id_start = it1;
175 566 : while (it1 != end &&
176 401 : *it1 != ':' &&
177 362 : *it1 != '}')
178 : {
179 165 : ++it1;
180 : }
181 236 : core::string_view id(id_start, it1);
182 :
183 : // move to specs part
184 236 : if (it1 != end &&
185 236 : *it1 == ':')
186 39 : ++it1;
187 236 : pctx.advance_to( it1 );
188 :
189 : // get format_arg to use
190 : auto idv = grammar::parse(
191 236 : id, grammar::unsigned_rule<std::size_t>{});
192 236 : if (idv)
193 : {
194 27 : fctx.arg( *idv ).format( pctx, fctx, cs );
195 : }
196 209 : else if (!id.empty())
197 : {
198 26 : fctx.arg( id ).format( pctx, fctx, cs );
199 : }
200 : else
201 : {
202 183 : std::size_t arg_id = pctx.next_arg_id();
203 183 : fctx.arg( arg_id ).format( pctx, fctx, cs );
204 : }
205 :
206 236 : it1 = pctx.begin();
207 236 : BOOST_ASSERT(*it1 == '}');
208 236 : it0 = it1 + 1;
209 : }
210 :
211 245 : return fctx.out();
212 : }
213 :
214 : } // detail
215 : } // urls
216 : } // boost
217 :
218 : #endif
|