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 :
11 : #include <boost/url/detail/config.hpp>
12 : #include "pct_format.hpp"
13 : #include <boost/url/grammar/parse.hpp>
14 : #include <boost/url/grammar/unsigned_rule.hpp>
15 :
16 : namespace boost {
17 : namespace urls {
18 : namespace detail {
19 :
20 : std::size_t
21 297 : pct_vmeasure(
22 : grammar::lut_chars const& cs,
23 : format_parse_context& pctx,
24 : measure_context& mctx)
25 : {
26 297 : auto it0 = pctx.begin();
27 297 : auto end = pctx.end();
28 581 : while( it0 != end )
29 : {
30 : // look for replacement id
31 348 : char const* it1 = it0;
32 348 : while(
33 902 : it1 != end &&
34 840 : *it1 != '{' )
35 : {
36 554 : ++it1;
37 : }
38 :
39 : // output literal prefix
40 348 : if( it0 != it1 )
41 : {
42 693 : for (char const* i = it0; i != it1; ++i)
43 554 : mctx.advance_to( mctx.out() + measure_one(*i, cs));
44 : }
45 :
46 : // over
47 348 : if( it1 == end )
48 : {
49 62 : break;
50 : }
51 :
52 : // enter replacement id
53 286 : ++it1;
54 286 : BOOST_ASSERT(it1 != end);
55 :
56 : // handle escaped replacement (second '{')
57 : // there's no "{{" in URL templates because
58 : // '{'s are not allowed in URLs
59 286 : BOOST_ASSERT(*it1 != '{');
60 : /*
61 : if( *it1 == '{' )
62 : {
63 : mctx.advance_to( mctx.out() + measure_one('{', cs));
64 : ++it1;
65 : // this was not a real replacement,
66 : // so we just keep moving
67 : continue;
68 : }
69 : */
70 :
71 :
72 : // parse {id} or {id:specs}
73 286 : char const* id_start = it1;
74 286 : while (it1 != end &&
75 536 : *it1 != ':' &&
76 495 : *it1 != '}')
77 : {
78 250 : ++it1;
79 : }
80 286 : core::string_view id(id_start, it1);
81 :
82 : // move to specs start
83 286 : if (it1 != end &&
84 286 : *it1 == ':')
85 41 : ++it1;
86 286 : pctx.advance_to( it1 );
87 :
88 : // get format_arg to use
89 286 : auto idv = grammar::parse(
90 286 : id, grammar::unsigned_rule<std::size_t>{});
91 286 : if (idv)
92 : {
93 33 : mctx.arg( *idv ).measure( pctx, mctx, cs );
94 : }
95 253 : else if (!id.empty())
96 : {
97 43 : mctx.arg( id ).measure( pctx, mctx, cs );
98 : }
99 : else
100 : {
101 210 : std::size_t arg_id = pctx.next_arg_id();
102 210 : mctx.arg( arg_id ).measure( pctx, mctx, cs );
103 : }
104 :
105 :
106 284 : it1 = pctx.begin();
107 284 : BOOST_ASSERT(*it1 == '}');
108 284 : it0 = it1 + 1;
109 : }
110 :
111 295 : return mctx.out();
112 : }
113 :
114 : char*
115 292 : pct_vformat(
116 : grammar::lut_chars const& cs,
117 : format_parse_context& pctx,
118 : format_context& fctx)
119 : {
120 292 : auto it0 = pctx.begin();
121 292 : auto end = pctx.end();
122 574 : while( it0 != end )
123 : {
124 : // look for replacement id
125 343 : char const* it1 = it0;
126 343 : while(
127 888 : it1 != end &&
128 827 : *it1 != '{' )
129 : {
130 545 : ++it1;
131 : }
132 :
133 : // output literal prefix
134 343 : if( it0 != it1 )
135 : {
136 683 : for (char const* i = it0; i != it1; ++i)
137 : {
138 545 : char* o = fctx.out();
139 545 : encode_one(o, *i, cs);
140 545 : fctx.advance_to(o);
141 : }
142 : }
143 :
144 : // over
145 343 : if( it1 == end )
146 : {
147 61 : break;
148 : }
149 :
150 : // enter replacement id
151 282 : ++it1;
152 282 : BOOST_ASSERT(it1 != end);
153 :
154 : // handle escaped replacement (second '{')
155 : // there's no "{{" in URL templates because
156 : // '{'s are not allowed in URLs
157 282 : BOOST_ASSERT(*it1 != '{');
158 : /*
159 : if( *it1 == '{' )
160 : {
161 : char* o = fctx.out();
162 : encode_one(o, '{', cs);
163 : fctx.advance_to(o);
164 : ++it1;
165 : // this was not a real replacement,
166 : // so we just keep moving
167 : continue;
168 : }
169 : */
170 :
171 : // parse {id} or {id:specs}
172 282 : char const* id_start = it1;
173 282 : while (it1 != end &&
174 532 : *it1 != ':' &&
175 493 : *it1 != '}')
176 : {
177 250 : ++it1;
178 : }
179 282 : core::string_view id(id_start, it1);
180 :
181 : // move to specs part
182 282 : if (it1 != end &&
183 282 : *it1 == ':')
184 39 : ++it1;
185 282 : pctx.advance_to( it1 );
186 :
187 : // get format_arg to use
188 282 : auto idv = grammar::parse(
189 282 : id, grammar::unsigned_rule<std::size_t>{});
190 282 : if (idv)
191 : {
192 33 : fctx.arg( *idv ).format( pctx, fctx, cs );
193 : }
194 249 : else if (!id.empty())
195 : {
196 43 : fctx.arg( id ).format( pctx, fctx, cs );
197 : }
198 : else
199 : {
200 206 : std::size_t arg_id = pctx.next_arg_id();
201 206 : fctx.arg( arg_id ).format( pctx, fctx, cs );
202 : }
203 :
204 282 : it1 = pctx.begin();
205 282 : BOOST_ASSERT(*it1 == '}');
206 282 : it0 = it1 + 1;
207 : }
208 :
209 292 : return fctx.out();
210 : }
211 :
212 : } // detail
213 : } // urls
214 : } // boost
215 :
|