OSDN Git Service

Change idx sub dir's time stamp when saving idx.
[fukui-no-namari/dialektos.git] / src / dat_parser.hxx
1 /*
2  * Copyright (C) 2009 by Aiwota Programmer
3  * aiwotaprog@tetteke.tk
4  *
5  * This file is part of Dialektos.
6  *
7  * Dialektos is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dialektos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dialektos.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #ifndef DAT_PARSER_HXX
22 #define DAT_PARSER_HXX
23
24 #include <algorithm>
25 #include <map>
26 #include <string>
27 #include <boost/range.hpp>
28 #include <boost/algorithm/string.hpp>
29
30
31 namespace dialektos {
32
33
34 /*! @brief DAT parser.
35
36 Supply text representing one 'res'.
37 Once parsing the 'res', the object must not be re-used.
38 You should prepare new object for next 'res'.
39 Template argument 'BufferBuilderT' must have interfaces
40 @code
41 class BufferBuilderT {
42 public:
43   void add_text(range, bold, href);
44   void add_id(range, bold, id);
45   void add_res_num(res_num, bold);
46   void new_line(left_margin);
47 };
48 @endcode
49 here 'range' is Boost.Range concepts.
50 DriverT is HTML parser driver template and
51 FunctionT is HTML parser functions template.
52 */
53 template <typename BufferBuilderT,
54 template <typename> class HtmlParserDriverT,
55 template <typename> class HtmlParserFunctionT>
56 class DatParser:
57   public HtmlParserDriverT<HtmlParserFunctionT<
58     DatParser<BufferBuilderT, HtmlParserDriverT, HtmlParserFunctionT> > > {
59 private:
60   typedef DatParser<BufferBuilderT,
61     HtmlParserDriverT, HtmlParserFunctionT> ThisClass;
62   typedef HtmlParserDriverT<HtmlParserFunctionT<ThisClass> > SuperClass;
63   using SuperClass::parse_html;
64
65   BufferBuilderT& buffer_builder_;
66   const int res_num_;
67   int left_margin_;
68   bool bold_;
69   std::string href_;
70   std::string buffer_;
71 public:
72
73   /*! @brief constructor. */
74   explicit DatParser(BufferBuilderT& view, int res_num):
75     buffer_builder_(view), res_num_(res_num), left_margin_(1), bold_(false),
76     href_() {
77   }
78
79   /*! @brief Supply text representing one 'res'. */
80   template<typename RangeT>
81   void operator()(const RangeT& range) {
82     drive_res_line(range);
83   }
84
85 public:
86   /*! @brief implementing FunctionT::on_data */
87   template <typename RangeT>
88   void on_data(const RangeT& range) {
89     buffer_ += std::string(boost::begin(range), boost::end(range));
90   }
91
92   /*! @brief implementing FunctionT::on_start_tag */
93   template <typename RangeT, typename MapT>
94   void on_start_tag(const RangeT& range,
95       const MapT& attrs) {
96     using boost::algorithm::equals;
97
98     flush();
99
100     if (equals(range, "br")) {
101       do_new_line();
102     } else if (equals(range, "b")) {
103       bold_ = true;
104     } else if (equals(range, "a")) {
105       typedef typename MapT::key_type KeyType;
106       typename MapT::const_iterator h = attrs.find(KeyType("href"));
107       if (h != attrs.end()) href_ = (*h).second;
108     }
109   }
110
111   /*! @brief implementing FunctionT::on_end_tag */
112   template <typename RangeT>
113   void on_end_tag(const RangeT& range) {
114     using boost::algorithm::equals;
115
116     flush();
117
118     if (equals(range, "b")) {
119       bold_ = false;
120     } else if (equals(range, "a")) {
121       href_.erase();
122     }
123   }
124
125 private:
126   /*! @brief BufferBuilderT must implement add_text(range, bold, href)*/
127   template <typename RangeT, typename RangeT2>
128   void add_text(const RangeT& range, bool bold, const RangeT2& href) {
129     buffer_builder_.add_text(range, bold, href);
130   }
131
132   /*! @brief BufferBuilderT must implement add_id(range, bold, id) */
133   template <typename RangeT, typename RangeT2>
134   void add_id(const RangeT& range, bool bold, const RangeT2& id) {
135     buffer_builder_.add_id(range, bold, id);
136   }
137
138   /*! @brief BufferBuilderT must implement add_res_num(res_num, bold) */
139   void add_res_num(int res_num, bool bold) {
140     buffer_builder_.add_res_num(res_num, bold);
141   }
142
143   /*! @brief BufferBuilderT must implement new_line(left_margin) */
144   void new_line(int left_margin) {
145     buffer_builder_.new_line(left_margin);
146   }
147
148 private:
149   void on_res_num() {
150
151     flush();
152
153     add_res_num(res_num_, bold_);
154   }
155
156   template <typename RangeT, typename RangeT2>
157   void on_id(const RangeT& range, const RangeT2& id) {
158
159     flush();
160
161     //buffer_builder_.add_text(range, bold_, id);
162     add_id(range, bold_, id);
163   }
164
165   void do_new_line() {
166     flush();
167     new_line(left_margin_);
168   }
169
170   void flush() {
171     if (!buffer_.empty()) {
172       add_text(buffer_, bold_, href_);
173       buffer_.clear();
174     }
175   }
176
177   template <typename RangeT>
178   void drive_res_line(const RangeT& range) {
179     typedef typename boost::range_const_iterator<RangeT>::type Iterator;
180     typedef typename boost::iterator_range<Iterator> IterRange;
181
182     if (boost::empty(range)) return;
183
184     boost::iterator_range<Iterator> name;
185     boost::iterator_range<Iterator> mail;
186     boost::iterator_range<Iterator> date;
187     boost::iterator_range<Iterator> msg;
188
189     enum Hogehoge {
190       HogeName, HogeMail, HogeDate, HogeMsg, HogeEnd
191     };
192     Hogehoge state = HogeName;
193
194     for (Iterator it = boost::begin(range); it != boost::end(range);) {
195
196       boost::iterator_range<Iterator> rdlm(it, boost::end(range));
197       rdlm = boost::find_first(rdlm, "<>");
198       if (!rdlm) break;
199
200       Iterator dlm = boost::begin(rdlm);
201
202       it = skip_white_space(std::make_pair(it, dlm));
203
204       switch (state) {
205       case HogeName:
206         // Name
207         state = HogeMail;
208         name = std::make_pair(it, dlm);
209         break;
210       case HogeMail:
211         state = HogeDate;
212         mail = std::make_pair(it, dlm);
213         break;
214       case HogeDate:
215         state = HogeMsg;
216         date = std::make_pair(it, dlm);
217         break;
218       case HogeMsg:
219         state = HogeEnd;
220         msg = std::make_pair(it, dlm);
221         break;
222       case HogeEnd:
223         break;
224       }
225       it = boost::end(rdlm);
226     }
227
228     do_new_line();
229
230     on_res_num();
231     on_data(std::string(" "));
232
233     if (state != HogeEnd) {
234       // failure parsing the res line.
235       on_data(range);
236     } else {
237       parse_name(name);
238       parse_mail(mail);
239       parse_date(date);
240       left_margin_ = 20;
241       do_new_line();
242       parse_msg(msg);
243     }
244
245     flush();
246   }
247
248   template <typename RangeT>
249   void parse_name(const RangeT& range) {
250     parse_html(std::string("<b>"));
251     parse_html(range);
252     parse_html(std::string("</b>"));
253   }
254
255   template <typename RangeT>
256   void parse_mail(const RangeT& range) {
257     on_data(std::string("["));
258     parse_html(range);
259     on_data(std::string("]"));
260   }
261
262   template <typename RangeT>
263   void parse_date(const RangeT& range) {
264     typedef typename boost::range_const_iterator<RangeT>::type Iterator;
265     typedef typename boost::iterator_range<Iterator> IterRange;
266
267     IterRange id = range;
268     id = boost::find_first(range, "ID:");
269     if (id) {
270       on_data(std::make_pair(boost::begin(range), boost::begin(id)));
271       Iterator id_end = std::find(boost::end(id), boost::end(range), ' ');
272
273       on_id(id, std::make_pair(boost::end(id), id_end));
274       on_data(std::make_pair(boost::end(id), boost::end(range)));
275     } else {
276       on_data(range);
277     }
278   }
279
280   template <typename RangeT>
281   void parse_msg(const RangeT& range) {
282     parse_html(range);
283   }
284
285 };
286
287
288 /*! @brief helper function for running DatParser. */
289 template <
290   template <typename> class HtmlParserDriverT,
291   template <typename> class HtmlParserFunctionT,
292   typename BufferBuilderT,
293   typename RangeT>
294 void run_parser(BufferBuilderT& view, const RangeT& range, int res_num) {
295   DatParser<BufferBuilderT, HtmlParserDriverT, HtmlParserFunctionT>
296   parser(view, res_num);
297   parser(range);
298 }
299
300 } // namespace dialektos
301
302 #endif