]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp
1 /*=============================================================================
2 Copyright (c) 2002-2003 Joel de Guzman
3 http://spirit.sourceforge.net/
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #include <boost/spirit/include/classic_core.hpp>
10 #include <boost/spirit/include/classic_push_back_actor.hpp>
11 #include <boost/spirit/include/classic_if.hpp>
12 #include <boost/spirit/include/classic_for.hpp>
13 #include <boost/spirit/include/phoenix1.hpp>
19 ///////////////////////////////////////////////////////////////////////////////
21 // Sample parser for binary data. This sample highlights the use of dynamic
22 // parsing where the result of actions direct the actual parsing behavior.
23 // We shall demonstrate 1) the use of phoenix to implement lambda (unnamed)
24 // functions, 2) dynamic looping using for_p, 3) the push_back_a actor for
25 // stuffing data into a vector, and 4) the if_p parser for choosing parser
26 // branches based on semantic conditions.
28 // << Sample idea by Florian Weimer >>
30 // For simplicity, we shall use bytes as atoms (and not 16-bit quantities
31 // in big-endian format or something similar, which would be more realistic)
32 // and PASCAL strings.
34 // A packet is the literal octet with value 255, followed by a variable
35 // octet N (denoting the total length of the packet), followed by N-2 octets
36 // (the payload). The payload contains a variable-length header, followed
37 // by zero or more elements.
39 // The header contains a single PASCAL string.
41 // An element is a PASCAL string (alternative: an element is an octet M,
42 // followed by [M/8] bytes, i.e. the necessary number of bytes to store M
45 // (This data structure is inspired by the format of a BGP UPDATE message.)
49 // .-------------------.
51 // +-------------------+ |
52 // | packet length | |
53 // +-------------------+ | number of bytes indicated by packet length
57 // `-------------------'
61 // .-------------------.
63 // +-------------------+
64 // | header octets | ^
65 // : : | number of octets given by header length
68 // +-------------------+
70 // : : | IPv4 prefixes have variable length (see
71 // +-------------------+ | below). The number of prefixes is
72 // | IPv4 prefix | | determined by the packet length.
74 // +-------------------+ |
79 // IPv4 prefix layout comes in five variants, depending on the first
82 // .-------------------.
83 // | 0x00 | single octet, corresponds to 0.0.0.0/0
84 // `-------------------'
86 // .-------------------.
87 // | 0x01 to 0x08 | two octets, prefix lengths up to /8.
88 // +-------------------+
90 // `-------------------'
92 // .-------------------.
93 // | 0x09 to 0x10 | three octets, prefix lengths up to /16.
94 // +-------------------+
96 // +-------------------+
98 // `-------------------'
100 // .-------------------.
101 // | 0x11 to 0x18 | four octets, prefix lengths up to /24.
102 // +-------------------+
103 // | MSB of network |
104 // +-------------------+
106 // +-------------------+
108 // `-------------------'
110 // .-------------------.
111 // | 0x19 to 0x20 | five octets, prefix lengths up to /32.
112 // +-------------------+
113 // | MSB of network |
114 // +-------------------+
116 // +-------------------+
118 // +-------------------+
119 // | LSB of network |
120 // `-------------------'
122 ///////////////////////////////////////////////////////////////////////////////
124 using namespace BOOST_SPIRIT_CLASSIC_NS
;
125 using namespace phoenix
;
127 struct ipv4_prefix_data
129 char prefix_len
, n0
, n1
, n2
, n3
;
132 : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}
137 char packet_len
, header_len
;
139 std::vector
<ipv4_prefix_data
> prefixes
;
142 : packet_len(0),header_len(0){}
146 struct ipv4
: public grammar
<ipv4
>
148 template <typename ScannerT
>
151 definition(ipv4
const& self
)
155 >> anychar_p
[var(self
.data
.packet_len
) = arg1
]
160 anychar_p
[var(self
.data
.header_len
) = arg1
]
161 >> for_p(var(i
) = 0, var(i
) < var(self
.data
.header_len
), ++var(i
))
163 anychar_p
[var(self
.data
.header
) += arg1
]
171 var(temp
.prefix_len
) = arg1
,
178 >> if_p(var(temp
.prefix_len
) > 0x00)
180 anychar_p
[var(temp
.n0
) = arg1
]
181 >> if_p(var(temp
.prefix_len
) > 0x08)
183 anychar_p
[var(temp
.n1
) = arg1
]
184 >> if_p(var(temp
.prefix_len
) > 0x10)
186 anychar_p
[var(temp
.n2
) = arg1
]
187 >> if_p(var(temp
.prefix_len
) > 0x18)
189 anychar_p
[var(temp
.n3
) = arg1
]
195 push_back_a(self
.data
.prefixes
, temp
)
201 ipv4_prefix_data temp
;
202 rule
<ScannerT
> packet
, payload
, ipv4_prefix
;
203 rule
<ScannerT
> const&
204 start() const { return packet
; }
207 ipv4(ipv4_data
& data
)
213 ////////////////////////////////////////////////////////////////////////////
217 ////////////////////////////////////////////////////////////////////////////
227 print_prefix(ipv4_prefix_data
const& prefix
)
229 cout
<< "prefix length = " << as_byte(prefix
.prefix_len
) << endl
;
230 cout
<< "n0 = " << as_byte(prefix
.n0
) << endl
;
231 cout
<< "n1 = " << as_byte(prefix
.n1
) << endl
;
232 cout
<< "n2 = " << as_byte(prefix
.n2
) << endl
;
233 cout
<< "n3 = " << as_byte(prefix
.n3
) << endl
;
237 parse_ipv4(char const* str
, unsigned len
)
241 parse_info
<> info
= parse(str
, str
+len
, g
);
245 cout
<< "-------------------------\n";
246 cout
<< "Parsing succeeded\n";
248 cout
<< "packet length = " << as_byte(data
.packet_len
) << endl
;
249 cout
<< "header length = " << as_byte(data
.header_len
) << endl
;
250 cout
<< "header = " << data
.header
<< endl
;
252 for_each(data
.prefixes
.begin(), data
.prefixes
.end(), print_prefix
);
253 cout
<< "-------------------------\n";
257 cout
<< "Parsing failed\n";
258 cout
<< "stopped at:";
259 for (char const* s
= info
.stop
; s
!= str
+len
; ++s
)
260 cout
<< static_cast<int>(*s
) << endl
;
266 // The string in the header is "empty", the prefix list is empty.
273 // The string in the header is "default route", the prefix list
274 // has just one element, 0.0.0.0/0.
278 'd','e','f','a','u','l','t',' ',
283 // The string in the header is "private address space", the prefix list
284 // has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
288 'p','r','i','v','a','t','e',' ',
289 'a','d','d','r','e','s','s',' ',
299 parse_ipv4(i1
, sizeof(i1
));
300 parse_ipv4(i2
, sizeof(i2
));
301 parse_ipv4(i3
, sizeof(i3
));