• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2002-2003 Joel de Guzman
3     http://spirit.sourceforge.net/
4 
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>
14 #include <iostream>
15 #include <string>
16 #include <vector>
17 #include <algorithm>
18 
19 ///////////////////////////////////////////////////////////////////////////////
20 //
21 //  Please check it out ipv4.cpp sample first!
22 //  << See ipv4.cpp sample for details >>
23 //
24 //  This is a variation of the ipv4.cpp sample. The original ipv4.cpp code
25 //  compiles to 36k on MSVC7.1. Not bad! Yet, we want to shave a little bit
26 //  more. Is it possible? Yes! This time, we'll use subrules and just store
27 //  the rules in a plain old struct. We are parsing at the char level anyway,
28 //  so we know what type of rule we'll need: a plain rule<>. The result: we
29 //  shaved off another 20k. Now the code compiles to 16k on MSVC7.1.
30 //
31 //  Could we have done better? Yes, but only if only we had typeof! << See
32 //  the techniques section of the User's guide >> ... Someday... :-)
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 using namespace std;
36 using namespace BOOST_SPIRIT_CLASSIC_NS;
37 using namespace phoenix;
38 
39 struct ipv4_prefix_data
40 {
41     char prefix_len, n0, n1, n2, n3;
42 
ipv4_prefix_dataipv4_prefix_data43     ipv4_prefix_data()
44         : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}
45 };
46 
47 struct ipv4_data
48 {
49     char packet_len, header_len;
50     std::string header;
51     std::vector<ipv4_prefix_data> prefixes;
52 
ipv4_dataipv4_data53     ipv4_data()
54         : packet_len(0),header_len(0){}
55 
56 };
57 
58 struct ipv4
59 {
ipv4ipv460     ipv4(ipv4_data& data)
61         : data(data)
62     {
63         start =
64         (
65             packet =
66                 '\xff'
67                 >> anychar_p[var(data.packet_len) = arg1]
68                 >> payload
69             ,
70 
71             payload =
72                 anychar_p[var(data.header_len) = arg1]
73                 >>  for_p(var(i) = 0, var(i) < var(data.header_len), ++var(i))
74                     [
75                         anychar_p[var(data.header) += arg1]
76                     ]
77                 >> *ipv4_prefix
78              ,
79 
80             ipv4_prefix =
81                 anychar_p
82                 [
83                     var(temp.prefix_len) = arg1,
84                     var(temp.n0) = 0,
85                     var(temp.n1) = 0,
86                     var(temp.n2) = 0,
87                     var(temp.n3) = 0
88                 ]
89 
90                 >>  if_p(var(temp.prefix_len) > 0x00)
91                     [
92                         anychar_p[var(temp.n0) = arg1]
93                         >>  if_p(var(temp.prefix_len) > 0x08)
94                             [
95                                 anychar_p[var(temp.n1) = arg1]
96                                 >>  if_p(var(temp.prefix_len) > 0x10)
97                                     [
98                                         anychar_p[var(temp.n2) = arg1]
99                                         >>  if_p(var(temp.prefix_len) > 0x18)
100                                             [
101                                                 anychar_p[var(temp.n3) = arg1]
102                                             ]
103                                     ]
104                             ]
105                     ]
106                     [
107                         push_back_a(data.prefixes, temp)
108                     ]
109         );
110     }
111 
112     int i;
113     ipv4_prefix_data temp;
114 
115     rule<> start;
116     subrule<0> packet;
117     subrule<1> payload;
118     subrule<2> ipv4_prefix;
119     ipv4_data& data;
120 };
121 
122 ////////////////////////////////////////////////////////////////////////////
123 //
124 //  Main program
125 //
126 ////////////////////////////////////////////////////////////////////////////
127 int
as_byte(char n)128 as_byte(char n)
129 {
130     if (n < 0)
131         return n + 256;
132     return n;
133 }
134 
135 void
print_prefix(ipv4_prefix_data const & prefix)136 print_prefix(ipv4_prefix_data const& prefix)
137 {
138     cout << "prefix length = " << as_byte(prefix.prefix_len) << endl;
139     cout << "n0 = " << as_byte(prefix.n0) << endl;
140     cout << "n1 = " << as_byte(prefix.n1) << endl;
141     cout << "n2 = " << as_byte(prefix.n2) << endl;
142     cout << "n3 = " << as_byte(prefix.n3) << endl;
143 }
144 
145 void
parse_ipv4(char const * str,unsigned len)146 parse_ipv4(char const* str, unsigned len)
147 {
148     ipv4_data data;
149     ipv4 g(data);
150     parse_info<> info = parse(str, str+len, g.start);
151 
152     if (info.full)
153     {
154         cout << "-------------------------\n";
155         cout << "Parsing succeeded\n";
156 
157         cout << "packet length = " << as_byte(data.packet_len) << endl;
158         cout << "header length = " << as_byte(data.header_len) << endl;
159         cout << "header = " << data.header << endl;
160 
161         for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix);
162         cout << "-------------------------\n";
163     }
164     else
165     {
166         cout << "Parsing failed\n";
167         cout << "stopped at:";
168         for (char const* s = info.stop; s != str+len; ++s)
169             cout << static_cast<int>(*s) << endl;
170     }
171 }
172 
173 // Test inputs:
174 
175 // The string in the header is "empty", the prefix list is empty.
176 char const i1[8] =
177 {
178     0xff,0x08,0x05,
179     'e','m','p','t','y'
180 };
181 
182 // The string in the header is "default route", the prefix list
183 // has just one element, 0.0.0.0/0.
184 char const i2[17] =
185 {
186     0xff,0x11,0x0d,
187     'd','e','f','a','u','l','t',' ',
188     'r','o','u','t','e',
189     0x00
190 };
191 
192 // The string in the header is "private address space", the prefix list
193 // has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
194 char const i3[32] =
195 {
196     0xff,0x20,0x15,
197     'p','r','i','v','a','t','e',' ',
198     'a','d','d','r','e','s','s',' ',
199     's','p','a','c','e',
200     0x08,0x0a,
201     0x0c,0xac,0x10,
202     0x10,0xc0,0xa8
203 };
204 
205 int
main()206 main()
207 {
208     parse_ipv4(i1, sizeof(i1));
209     parse_ipv4(i2, sizeof(i2));
210     parse_ipv4(i3, sizeof(i3));
211     return 0;
212 }
213 
214