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