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 250 : pct_vmeasure(
22 : grammar::lut_chars const& cs,
23 : format_parse_context& pctx,
24 : measure_context& mctx)
25 : {
26 250 : auto it0 = pctx.begin();
27 250 : auto end = pctx.end();
28 488 : while( it0 != end )
29 : {
30 : // look for replacement id
31 295 : char const* it1 = it0;
32 295 : while(
33 762 : it1 != end &&
34 707 : *it1 != '{' )
35 : {
36 467 : ++it1;
37 : }
38 :
39 : // output literal prefix
40 295 : if( it0 != it1 )
41 : {
42 584 : for (char const* i = it0; i != it1; ++i)
43 467 : mctx.advance_to( mctx.out() + measure_one(*i, cs));
44 : }
45 :
46 : // over
47 295 : if( it1 == end )
48 : {
49 55 : break;
50 : }
51 :
52 : // enter replacement id
53 240 : ++it1;
54 240 : 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 240 : 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 240 : char const* id_start = it1;
74 240 : while (it1 != end &&
75 405 : *it1 != ':' &&
76 364 : *it1 != '}')
77 : {
78 165 : ++it1;
79 : }
80 240 : core::string_view id(id_start, it1);
81 :
82 : // move to specs start
83 240 : if (it1 != end &&
84 240 : *it1 == ':')
85 41 : ++it1;
86 240 : pctx.advance_to( it1 );
87 :
88 : // get format_arg to use
89 240 : auto idv = grammar::parse(
90 240 : id, grammar::unsigned_rule<std::size_t>{});
91 240 : if (idv)
92 : {
93 27 : mctx.arg( *idv ).measure( pctx, mctx, cs );
94 : }
95 213 : else if (!id.empty())
96 : {
97 26 : mctx.arg( id ).measure( pctx, mctx, cs );
98 : }
99 : else
100 : {
101 187 : std::size_t arg_id = pctx.next_arg_id();
102 187 : mctx.arg( arg_id ).measure( pctx, mctx, cs );
103 : }
104 :
105 :
106 238 : it1 = pctx.begin();
107 238 : BOOST_ASSERT(*it1 == '}');
108 238 : it0 = it1 + 1;
109 : }
110 :
111 248 : return mctx.out();
112 : }
113 :
114 : char*
115 245 : pct_vformat(
116 : grammar::lut_chars const& cs,
117 : format_parse_context& pctx,
118 : format_context& fctx)
119 : {
120 245 : auto it0 = pctx.begin();
121 245 : auto end = pctx.end();
122 481 : while( it0 != end )
123 : {
124 : // look for replacement id
125 290 : char const* it1 = it0;
126 290 : while(
127 748 : it1 != end &&
128 694 : *it1 != '{' )
129 : {
130 458 : ++it1;
131 : }
132 :
133 : // output literal prefix
134 290 : if( it0 != it1 )
135 : {
136 574 : for (char const* i = it0; i != it1; ++i)
137 : {
138 458 : char* o = fctx.out();
139 458 : encode_one(o, *i, cs);
140 458 : fctx.advance_to(o);
141 : }
142 : }
143 :
144 : // over
145 290 : if( it1 == end )
146 : {
147 54 : break;
148 : }
149 :
150 : // enter replacement id
151 236 : ++it1;
152 236 : 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 236 : 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 236 : char const* id_start = it1;
173 236 : while (it1 != end &&
174 401 : *it1 != ':' &&
175 362 : *it1 != '}')
176 : {
177 165 : ++it1;
178 : }
179 236 : core::string_view id(id_start, it1);
180 :
181 : // move to specs part
182 236 : if (it1 != end &&
183 236 : *it1 == ':')
184 39 : ++it1;
185 236 : pctx.advance_to( it1 );
186 :
187 : // get format_arg to use
188 236 : auto idv = grammar::parse(
189 236 : id, grammar::unsigned_rule<std::size_t>{});
190 236 : if (idv)
191 : {
192 27 : fctx.arg( *idv ).format( pctx, fctx, cs );
193 : }
194 209 : else if (!id.empty())
195 : {
196 26 : fctx.arg( id ).format( pctx, fctx, cs );
197 : }
198 : else
199 : {
200 183 : std::size_t arg_id = pctx.next_arg_id();
201 183 : fctx.arg( arg_id ).format( pctx, fctx, cs );
202 : }
203 :
204 236 : it1 = pctx.begin();
205 236 : BOOST_ASSERT(*it1 == '}');
206 236 : it0 = it1 + 1;
207 : }
208 :
209 245 : return fctx.out();
210 : }
211 :
212 : } // detail
213 : } // urls
214 : } // boost
215 :
|