5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12 #define BOOST_ASIO_IMPL_READ_UNTIL_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
22 #include <boost/asio/buffer.hpp>
23 #include <boost/asio/buffers_iterator.hpp>
24 #include <boost/asio/detail/bind_handler.hpp>
25 #include <boost/asio/detail/handler_alloc_helpers.hpp>
26 #include <boost/asio/detail/handler_cont_helpers.hpp>
27 #include <boost/asio/detail/handler_invoke_helpers.hpp>
28 #include <boost/asio/detail/handler_type_requirements.hpp>
29 #include <boost/asio/detail/limits.hpp>
30 #include <boost/asio/detail/throw_error.hpp>
32 #include <boost/asio/detail/push_options.hpp>
37 template <typename SyncReadStream, typename Allocator>
38 inline std::size_t read_until(SyncReadStream& s,
39 boost::asio::basic_streambuf<Allocator>& b, char delim)
41 boost::system::error_code ec;
42 std::size_t bytes_transferred = read_until(s, b, delim, ec);
43 boost::asio::detail::throw_error(ec, "read_until");
44 return bytes_transferred;
47 template <typename SyncReadStream, typename Allocator>
48 std::size_t read_until(SyncReadStream& s,
49 boost::asio::basic_streambuf<Allocator>& b, char delim,
50 boost::system::error_code& ec)
52 std::size_t search_position = 0;
55 // Determine the range of the data to be searched.
56 typedef typename boost::asio::basic_streambuf<
57 Allocator>::const_buffers_type const_buffers_type;
58 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
59 const_buffers_type buffers = b.data();
60 iterator begin = iterator::begin(buffers);
61 iterator start_pos = begin + search_position;
62 iterator end = iterator::end(buffers);
65 iterator iter = std::find(start_pos, end, delim);
68 // Found a match. We're done.
69 ec = boost::system::error_code();
70 return iter - begin + 1;
74 // No match. Next search can start with the new data.
75 search_position = end - begin;
78 // Check if buffer is full.
79 if (b.size() == b.max_size())
81 ec = error::not_found;
86 std::size_t bytes_to_read = read_size_helper(b, 65536);
87 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
93 template <typename SyncReadStream, typename Allocator>
94 inline std::size_t read_until(SyncReadStream& s,
95 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim)
97 boost::system::error_code ec;
98 std::size_t bytes_transferred = read_until(s, b, delim, ec);
99 boost::asio::detail::throw_error(ec, "read_until");
100 return bytes_transferred;
105 // Algorithm that finds a subsequence of equal values in a sequence. Returns
106 // (iterator,true) if a full match was found, in which case the iterator
107 // points to the beginning of the match. Returns (iterator,false) if a
108 // partial match was found at the end of the first sequence, in which case
109 // the iterator points to the beginning of the partial match. Returns
110 // (last1,false) if no full or partial match was found.
111 template <typename Iterator1, typename Iterator2>
112 std::pair<Iterator1, bool> partial_search(
113 Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
115 for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
117 Iterator1 test_iter1 = iter1;
118 Iterator2 test_iter2 = first2;
119 for (;; ++test_iter1, ++test_iter2)
121 if (test_iter2 == last2)
122 return std::make_pair(iter1, true);
123 if (test_iter1 == last1)
125 if (test_iter2 != first2)
126 return std::make_pair(iter1, false);
130 if (*test_iter1 != *test_iter2)
134 return std::make_pair(last1, false);
136 } // namespace detail
138 template <typename SyncReadStream, typename Allocator>
139 std::size_t read_until(SyncReadStream& s,
140 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
141 boost::system::error_code& ec)
143 std::size_t search_position = 0;
146 // Determine the range of the data to be searched.
147 typedef typename boost::asio::basic_streambuf<
148 Allocator>::const_buffers_type const_buffers_type;
149 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
150 const_buffers_type buffers = b.data();
151 iterator begin = iterator::begin(buffers);
152 iterator start_pos = begin + search_position;
153 iterator end = iterator::end(buffers);
156 std::pair<iterator, bool> result = detail::partial_search(
157 start_pos, end, delim.begin(), delim.end());
158 if (result.first != end)
162 // Full match. We're done.
163 ec = boost::system::error_code();
164 return result.first - begin + delim.length();
168 // Partial match. Next search needs to start from beginning of match.
169 search_position = result.first - begin;
174 // No match. Next search can start with the new data.
175 search_position = end - begin;
178 // Check if buffer is full.
179 if (b.size() == b.max_size())
181 ec = error::not_found;
186 std::size_t bytes_to_read = read_size_helper(b, 65536);
187 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
193 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
195 template <typename SyncReadStream, typename Allocator>
196 inline std::size_t read_until(SyncReadStream& s,
197 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
199 boost::system::error_code ec;
200 std::size_t bytes_transferred = read_until(s, b, expr, ec);
201 boost::asio::detail::throw_error(ec, "read_until");
202 return bytes_transferred;
205 template <typename SyncReadStream, typename Allocator>
206 std::size_t read_until(SyncReadStream& s,
207 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
208 boost::system::error_code& ec)
210 std::size_t search_position = 0;
213 // Determine the range of the data to be searched.
214 typedef typename boost::asio::basic_streambuf<
215 Allocator>::const_buffers_type const_buffers_type;
216 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
217 const_buffers_type buffers = b.data();
218 iterator begin = iterator::begin(buffers);
219 iterator start_pos = begin + search_position;
220 iterator end = iterator::end(buffers);
223 boost::match_results<iterator,
224 typename std::vector<boost::sub_match<iterator> >::allocator_type>
226 if (regex_search(start_pos, end, match_results, expr,
227 boost::match_default | boost::match_partial))
229 if (match_results[0].matched)
231 // Full match. We're done.
232 ec = boost::system::error_code();
233 return match_results[0].second - begin;
237 // Partial match. Next search needs to start from beginning of match.
238 search_position = match_results[0].first - begin;
243 // No match. Next search can start with the new data.
244 search_position = end - begin;
247 // Check if buffer is full.
248 if (b.size() == b.max_size())
250 ec = error::not_found;
255 std::size_t bytes_to_read = read_size_helper(b, 65536);
256 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
262 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
264 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
265 std::size_t read_until(SyncReadStream& s,
266 boost::asio::basic_streambuf<Allocator>& b,
267 MatchCondition match_condition, boost::system::error_code& ec,
268 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
270 std::size_t search_position = 0;
273 // Determine the range of the data to be searched.
274 typedef typename boost::asio::basic_streambuf<
275 Allocator>::const_buffers_type const_buffers_type;
276 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
277 const_buffers_type buffers = b.data();
278 iterator begin = iterator::begin(buffers);
279 iterator start_pos = begin + search_position;
280 iterator end = iterator::end(buffers);
283 std::pair<iterator, bool> result = match_condition(start_pos, end);
286 // Full match. We're done.
287 ec = boost::system::error_code();
288 return result.first - begin;
290 else if (result.first != end)
292 // Partial match. Next search needs to start from beginning of match.
293 search_position = result.first - begin;
297 // No match. Next search can start with the new data.
298 search_position = end - begin;
301 // Check if buffer is full.
302 if (b.size() == b.max_size())
304 ec = error::not_found;
309 std::size_t bytes_to_read = read_size_helper(b, 65536);
310 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
316 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
317 inline std::size_t read_until(SyncReadStream& s,
318 boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
319 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
321 boost::system::error_code ec;
322 std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
323 boost::asio::detail::throw_error(ec, "read_until");
324 return bytes_transferred;
329 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
330 class read_until_delim_op
333 read_until_delim_op(AsyncReadStream& stream,
334 boost::asio::basic_streambuf<Allocator>& streambuf,
335 char delim, ReadHandler& handler)
337 streambuf_(streambuf),
341 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
345 #if defined(BOOST_ASIO_HAS_MOVE)
346 read_until_delim_op(const read_until_delim_op& other)
347 : stream_(other.stream_),
348 streambuf_(other.streambuf_),
349 delim_(other.delim_),
350 start_(other.start_),
351 search_position_(other.search_position_),
352 handler_(other.handler_)
356 read_until_delim_op(read_until_delim_op&& other)
357 : stream_(other.stream_),
358 streambuf_(other.streambuf_),
359 delim_(other.delim_),
360 start_(other.start_),
361 search_position_(other.search_position_),
362 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
365 #endif // defined(BOOST_ASIO_HAS_MOVE)
367 void operator()(const boost::system::error_code& ec,
368 std::size_t bytes_transferred, int start = 0)
370 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
371 std::size_t bytes_to_read;
372 switch (start_ = start)
378 // Determine the range of the data to be searched.
379 typedef typename boost::asio::basic_streambuf<
380 Allocator>::const_buffers_type const_buffers_type;
381 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
382 const_buffers_type buffers = streambuf_.data();
383 iterator begin = iterator::begin(buffers);
384 iterator start_pos = begin + search_position_;
385 iterator end = iterator::end(buffers);
388 iterator iter = std::find(start_pos, end, delim_);
391 // Found a match. We're done.
392 search_position_ = iter - begin + 1;
396 // No match yet. Check if buffer is full.
397 else if (streambuf_.size() == streambuf_.max_size())
399 search_position_ = not_found;
403 // Need to read some more data.
406 // Next search can start with the new data.
407 search_position_ = end - begin;
408 bytes_to_read = read_size_helper(streambuf_, 65536);
412 // Check if we're done.
413 if (!start && bytes_to_read == 0)
416 // Start a new asynchronous read operation to obtain more data.
417 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
418 BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
420 streambuf_.commit(bytes_transferred);
421 if (ec || bytes_transferred == 0)
425 const boost::system::error_code result_ec =
426 (search_position_ == not_found)
427 ? error::not_found : ec;
429 const std::size_t result_n =
430 (ec || search_position_ == not_found)
431 ? 0 : search_position_;
433 handler_(result_ec, result_n);
438 AsyncReadStream& stream_;
439 boost::asio::basic_streambuf<Allocator>& streambuf_;
442 std::size_t search_position_;
443 ReadHandler handler_;
446 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
447 inline void* asio_handler_allocate(std::size_t size,
448 read_until_delim_op<AsyncReadStream,
449 Allocator, ReadHandler>* this_handler)
451 return boost_asio_handler_alloc_helpers::allocate(
452 size, this_handler->handler_);
455 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
456 inline void asio_handler_deallocate(void* pointer, std::size_t size,
457 read_until_delim_op<AsyncReadStream,
458 Allocator, ReadHandler>* this_handler)
460 boost_asio_handler_alloc_helpers::deallocate(
461 pointer, size, this_handler->handler_);
464 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
465 inline bool asio_handler_is_continuation(
466 read_until_delim_op<AsyncReadStream,
467 Allocator, ReadHandler>* this_handler)
469 return this_handler->start_ == 0 ? true
470 : boost_asio_handler_cont_helpers::is_continuation(
471 this_handler->handler_);
474 template <typename Function, typename AsyncReadStream, typename Allocator,
475 typename ReadHandler>
476 inline void asio_handler_invoke(Function& function,
477 read_until_delim_op<AsyncReadStream,
478 Allocator, ReadHandler>* this_handler)
480 boost_asio_handler_invoke_helpers::invoke(
481 function, this_handler->handler_);
484 template <typename Function, typename AsyncReadStream, typename Allocator,
485 typename ReadHandler>
486 inline void asio_handler_invoke(const Function& function,
487 read_until_delim_op<AsyncReadStream,
488 Allocator, ReadHandler>* this_handler)
490 boost_asio_handler_invoke_helpers::invoke(
491 function, this_handler->handler_);
493 } // namespace detail
495 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
496 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
497 void (boost::system::error_code, std::size_t))
498 async_read_until(AsyncReadStream& s,
499 boost::asio::basic_streambuf<Allocator>& b, char delim,
500 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
502 // If you get an error on the following line it means that your handler does
503 // not meet the documented type requirements for a ReadHandler.
504 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
506 detail::async_result_init<
507 ReadHandler, void (boost::system::error_code, std::size_t)> init(
508 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
510 detail::read_until_delim_op<AsyncReadStream,
511 Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
512 void (boost::system::error_code, std::size_t))>(
513 s, b, delim, init.handler)(
514 boost::system::error_code(), 0, 1);
516 return init.result.get();
521 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
522 class read_until_delim_string_op
525 read_until_delim_string_op(AsyncReadStream& stream,
526 boost::asio::basic_streambuf<Allocator>& streambuf,
527 const std::string& delim, ReadHandler& handler)
529 streambuf_(streambuf),
533 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
537 #if defined(BOOST_ASIO_HAS_MOVE)
538 read_until_delim_string_op(const read_until_delim_string_op& other)
539 : stream_(other.stream_),
540 streambuf_(other.streambuf_),
541 delim_(other.delim_),
542 start_(other.start_),
543 search_position_(other.search_position_),
544 handler_(other.handler_)
548 read_until_delim_string_op(read_until_delim_string_op&& other)
549 : stream_(other.stream_),
550 streambuf_(other.streambuf_),
551 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
552 start_(other.start_),
553 search_position_(other.search_position_),
554 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
557 #endif // defined(BOOST_ASIO_HAS_MOVE)
559 void operator()(const boost::system::error_code& ec,
560 std::size_t bytes_transferred, int start = 0)
562 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
563 std::size_t bytes_to_read;
564 switch (start_ = start)
570 // Determine the range of the data to be searched.
571 typedef typename boost::asio::basic_streambuf<
572 Allocator>::const_buffers_type const_buffers_type;
573 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
574 const_buffers_type buffers = streambuf_.data();
575 iterator begin = iterator::begin(buffers);
576 iterator start_pos = begin + search_position_;
577 iterator end = iterator::end(buffers);
580 std::pair<iterator, bool> result = detail::partial_search(
581 start_pos, end, delim_.begin(), delim_.end());
582 if (result.first != end && result.second)
584 // Full match. We're done.
585 search_position_ = result.first - begin + delim_.length();
589 // No match yet. Check if buffer is full.
590 else if (streambuf_.size() == streambuf_.max_size())
592 search_position_ = not_found;
596 // Need to read some more data.
599 if (result.first != end)
601 // Partial match. Next search needs to start from beginning of
603 search_position_ = result.first - begin;
607 // Next search can start with the new data.
608 search_position_ = end - begin;
611 bytes_to_read = read_size_helper(streambuf_, 65536);
615 // Check if we're done.
616 if (!start && bytes_to_read == 0)
619 // Start a new asynchronous read operation to obtain more data.
620 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
621 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
623 streambuf_.commit(bytes_transferred);
624 if (ec || bytes_transferred == 0)
628 const boost::system::error_code result_ec =
629 (search_position_ == not_found)
630 ? error::not_found : ec;
632 const std::size_t result_n =
633 (ec || search_position_ == not_found)
634 ? 0 : search_position_;
636 handler_(result_ec, result_n);
641 AsyncReadStream& stream_;
642 boost::asio::basic_streambuf<Allocator>& streambuf_;
645 std::size_t search_position_;
646 ReadHandler handler_;
649 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
650 inline void* asio_handler_allocate(std::size_t size,
651 read_until_delim_string_op<AsyncReadStream,
652 Allocator, ReadHandler>* this_handler)
654 return boost_asio_handler_alloc_helpers::allocate(
655 size, this_handler->handler_);
658 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
659 inline void asio_handler_deallocate(void* pointer, std::size_t size,
660 read_until_delim_string_op<AsyncReadStream,
661 Allocator, ReadHandler>* this_handler)
663 boost_asio_handler_alloc_helpers::deallocate(
664 pointer, size, this_handler->handler_);
667 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
668 inline bool asio_handler_is_continuation(
669 read_until_delim_string_op<AsyncReadStream,
670 Allocator, ReadHandler>* this_handler)
672 return this_handler->start_ == 0 ? true
673 : boost_asio_handler_cont_helpers::is_continuation(
674 this_handler->handler_);
677 template <typename Function, typename AsyncReadStream,
678 typename Allocator, typename ReadHandler>
679 inline void asio_handler_invoke(Function& function,
680 read_until_delim_string_op<AsyncReadStream,
681 Allocator, ReadHandler>* this_handler)
683 boost_asio_handler_invoke_helpers::invoke(
684 function, this_handler->handler_);
687 template <typename Function, typename AsyncReadStream,
688 typename Allocator, typename ReadHandler>
689 inline void asio_handler_invoke(const Function& function,
690 read_until_delim_string_op<AsyncReadStream,
691 Allocator, ReadHandler>* this_handler)
693 boost_asio_handler_invoke_helpers::invoke(
694 function, this_handler->handler_);
696 } // namespace detail
698 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
699 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
700 void (boost::system::error_code, std::size_t))
701 async_read_until(AsyncReadStream& s,
702 boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
703 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
705 // If you get an error on the following line it means that your handler does
706 // not meet the documented type requirements for a ReadHandler.
707 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
709 detail::async_result_init<
710 ReadHandler, void (boost::system::error_code, std::size_t)> init(
711 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
713 detail::read_until_delim_string_op<AsyncReadStream,
714 Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
715 void (boost::system::error_code, std::size_t))>(
716 s, b, delim, init.handler)(
717 boost::system::error_code(), 0, 1);
719 return init.result.get();
722 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
726 template <typename AsyncReadStream, typename Allocator,
727 typename RegEx, typename ReadHandler>
728 class read_until_expr_op
731 read_until_expr_op(AsyncReadStream& stream,
732 boost::asio::basic_streambuf<Allocator>& streambuf,
733 const boost::regex& expr, ReadHandler& handler)
735 streambuf_(streambuf),
739 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
743 #if defined(BOOST_ASIO_HAS_MOVE)
744 read_until_expr_op(const read_until_expr_op& other)
745 : stream_(other.stream_),
746 streambuf_(other.streambuf_),
748 start_(other.start_),
749 search_position_(other.search_position_),
750 handler_(other.handler_)
754 read_until_expr_op(read_until_expr_op&& other)
755 : stream_(other.stream_),
756 streambuf_(other.streambuf_),
758 start_(other.start_),
759 search_position_(other.search_position_),
760 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
763 #endif // defined(BOOST_ASIO_HAS_MOVE)
765 void operator()(const boost::system::error_code& ec,
766 std::size_t bytes_transferred, int start = 0)
768 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
769 std::size_t bytes_to_read;
770 switch (start_ = start)
776 // Determine the range of the data to be searched.
777 typedef typename boost::asio::basic_streambuf<
778 Allocator>::const_buffers_type const_buffers_type;
779 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
780 const_buffers_type buffers = streambuf_.data();
781 iterator begin = iterator::begin(buffers);
782 iterator start_pos = begin + search_position_;
783 iterator end = iterator::end(buffers);
786 boost::match_results<iterator,
787 typename std::vector<boost::sub_match<iterator> >::allocator_type>
789 bool match = regex_search(start_pos, end, match_results, expr_,
790 boost::match_default | boost::match_partial);
791 if (match && match_results[0].matched)
793 // Full match. We're done.
794 search_position_ = match_results[0].second - begin;
798 // No match yet. Check if buffer is full.
799 else if (streambuf_.size() == streambuf_.max_size())
801 search_position_ = not_found;
805 // Need to read some more data.
810 // Partial match. Next search needs to start from beginning of
812 search_position_ = match_results[0].first - begin;
816 // Next search can start with the new data.
817 search_position_ = end - begin;
820 bytes_to_read = read_size_helper(streambuf_, 65536);
824 // Check if we're done.
825 if (!start && bytes_to_read == 0)
828 // Start a new asynchronous read operation to obtain more data.
829 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
830 BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
832 streambuf_.commit(bytes_transferred);
833 if (ec || bytes_transferred == 0)
837 const boost::system::error_code result_ec =
838 (search_position_ == not_found)
839 ? error::not_found : ec;
841 const std::size_t result_n =
842 (ec || search_position_ == not_found)
843 ? 0 : search_position_;
845 handler_(result_ec, result_n);
850 AsyncReadStream& stream_;
851 boost::asio::basic_streambuf<Allocator>& streambuf_;
854 std::size_t search_position_;
855 ReadHandler handler_;
858 template <typename AsyncReadStream, typename Allocator,
859 typename RegEx, typename ReadHandler>
860 inline void* asio_handler_allocate(std::size_t size,
861 read_until_expr_op<AsyncReadStream,
862 Allocator, RegEx, ReadHandler>* this_handler)
864 return boost_asio_handler_alloc_helpers::allocate(
865 size, this_handler->handler_);
868 template <typename AsyncReadStream, typename Allocator,
869 typename RegEx, typename ReadHandler>
870 inline void asio_handler_deallocate(void* pointer, std::size_t size,
871 read_until_expr_op<AsyncReadStream,
872 Allocator, RegEx, ReadHandler>* this_handler)
874 boost_asio_handler_alloc_helpers::deallocate(
875 pointer, size, this_handler->handler_);
878 template <typename AsyncReadStream, typename Allocator,
879 typename RegEx, typename ReadHandler>
880 inline bool asio_handler_is_continuation(
881 read_until_expr_op<AsyncReadStream,
882 Allocator, RegEx, ReadHandler>* this_handler)
884 return this_handler->start_ == 0 ? true
885 : boost_asio_handler_cont_helpers::is_continuation(
886 this_handler->handler_);
889 template <typename Function, typename AsyncReadStream, typename Allocator,
890 typename RegEx, typename ReadHandler>
891 inline void asio_handler_invoke(Function& function,
892 read_until_expr_op<AsyncReadStream,
893 Allocator, RegEx, ReadHandler>* this_handler)
895 boost_asio_handler_invoke_helpers::invoke(
896 function, this_handler->handler_);
899 template <typename Function, typename AsyncReadStream, typename Allocator,
900 typename RegEx, typename ReadHandler>
901 inline void asio_handler_invoke(const Function& function,
902 read_until_expr_op<AsyncReadStream,
903 Allocator, RegEx, ReadHandler>* this_handler)
905 boost_asio_handler_invoke_helpers::invoke(
906 function, this_handler->handler_);
908 } // namespace detail
910 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
911 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
912 void (boost::system::error_code, std::size_t))
913 async_read_until(AsyncReadStream& s,
914 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
915 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
917 // If you get an error on the following line it means that your handler does
918 // not meet the documented type requirements for a ReadHandler.
919 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
921 detail::async_result_init<
922 ReadHandler, void (boost::system::error_code, std::size_t)> init(
923 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
925 detail::read_until_expr_op<AsyncReadStream, Allocator,
926 boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
927 void (boost::system::error_code, std::size_t))>(
928 s, b, expr, init.handler)(
929 boost::system::error_code(), 0, 1);
931 return init.result.get();
934 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
938 template <typename AsyncReadStream, typename Allocator,
939 typename MatchCondition, typename ReadHandler>
940 class read_until_match_op
943 read_until_match_op(AsyncReadStream& stream,
944 boost::asio::basic_streambuf<Allocator>& streambuf,
945 MatchCondition match_condition, ReadHandler& handler)
947 streambuf_(streambuf),
948 match_condition_(match_condition),
951 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
955 #if defined(BOOST_ASIO_HAS_MOVE)
956 read_until_match_op(const read_until_match_op& other)
957 : stream_(other.stream_),
958 streambuf_(other.streambuf_),
959 match_condition_(other.match_condition_),
960 start_(other.start_),
961 search_position_(other.search_position_),
962 handler_(other.handler_)
966 read_until_match_op(read_until_match_op&& other)
967 : stream_(other.stream_),
968 streambuf_(other.streambuf_),
969 match_condition_(other.match_condition_),
970 start_(other.start_),
971 search_position_(other.search_position_),
972 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
975 #endif // defined(BOOST_ASIO_HAS_MOVE)
977 void operator()(const boost::system::error_code& ec,
978 std::size_t bytes_transferred, int start = 0)
980 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
981 std::size_t bytes_to_read;
982 switch (start_ = start)
988 // Determine the range of the data to be searched.
989 typedef typename boost::asio::basic_streambuf<
990 Allocator>::const_buffers_type const_buffers_type;
991 typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
992 const_buffers_type buffers = streambuf_.data();
993 iterator begin = iterator::begin(buffers);
994 iterator start_pos = begin + search_position_;
995 iterator end = iterator::end(buffers);
998 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1001 // Full match. We're done.
1002 search_position_ = result.first - begin;
1006 // No match yet. Check if buffer is full.
1007 else if (streambuf_.size() == streambuf_.max_size())
1009 search_position_ = not_found;
1013 // Need to read some more data.
1016 if (result.first != end)
1018 // Partial match. Next search needs to start from beginning of
1020 search_position_ = result.first - begin;
1024 // Next search can start with the new data.
1025 search_position_ = end - begin;
1028 bytes_to_read = read_size_helper(streambuf_, 65536);
1032 // Check if we're done.
1033 if (!start && bytes_to_read == 0)
1036 // Start a new asynchronous read operation to obtain more data.
1037 stream_.async_read_some(streambuf_.prepare(bytes_to_read),
1038 BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
1040 streambuf_.commit(bytes_transferred);
1041 if (ec || bytes_transferred == 0)
1045 const boost::system::error_code result_ec =
1046 (search_position_ == not_found)
1047 ? error::not_found : ec;
1049 const std::size_t result_n =
1050 (ec || search_position_ == not_found)
1051 ? 0 : search_position_;
1053 handler_(result_ec, result_n);
1058 AsyncReadStream& stream_;
1059 boost::asio::basic_streambuf<Allocator>& streambuf_;
1060 MatchCondition match_condition_;
1062 std::size_t search_position_;
1063 ReadHandler handler_;
1066 template <typename AsyncReadStream, typename Allocator,
1067 typename MatchCondition, typename ReadHandler>
1068 inline void* asio_handler_allocate(std::size_t size,
1069 read_until_match_op<AsyncReadStream,
1070 Allocator, MatchCondition, ReadHandler>* this_handler)
1072 return boost_asio_handler_alloc_helpers::allocate(
1073 size, this_handler->handler_);
1076 template <typename AsyncReadStream, typename Allocator,
1077 typename MatchCondition, typename ReadHandler>
1078 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1079 read_until_match_op<AsyncReadStream,
1080 Allocator, MatchCondition, ReadHandler>* this_handler)
1082 boost_asio_handler_alloc_helpers::deallocate(
1083 pointer, size, this_handler->handler_);
1086 template <typename AsyncReadStream, typename Allocator,
1087 typename MatchCondition, typename ReadHandler>
1088 inline bool asio_handler_is_continuation(
1089 read_until_match_op<AsyncReadStream,
1090 Allocator, MatchCondition, ReadHandler>* this_handler)
1092 return this_handler->start_ == 0 ? true
1093 : boost_asio_handler_cont_helpers::is_continuation(
1094 this_handler->handler_);
1097 template <typename Function, typename AsyncReadStream, typename Allocator,
1098 typename MatchCondition, typename ReadHandler>
1099 inline void asio_handler_invoke(Function& function,
1100 read_until_match_op<AsyncReadStream,
1101 Allocator, MatchCondition, ReadHandler>* this_handler)
1103 boost_asio_handler_invoke_helpers::invoke(
1104 function, this_handler->handler_);
1107 template <typename Function, typename AsyncReadStream, typename Allocator,
1108 typename MatchCondition, typename ReadHandler>
1109 inline void asio_handler_invoke(const Function& function,
1110 read_until_match_op<AsyncReadStream,
1111 Allocator, MatchCondition, ReadHandler>* this_handler)
1113 boost_asio_handler_invoke_helpers::invoke(
1114 function, this_handler->handler_);
1116 } // namespace detail
1118 template <typename AsyncReadStream, typename Allocator,
1119 typename MatchCondition, typename ReadHandler>
1120 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1121 void (boost::system::error_code, std::size_t))
1122 async_read_until(AsyncReadStream& s,
1123 boost::asio::basic_streambuf<Allocator>& b,
1124 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1125 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1127 // If you get an error on the following line it means that your handler does
1128 // not meet the documented type requirements for a ReadHandler.
1129 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1131 detail::async_result_init<
1132 ReadHandler, void (boost::system::error_code, std::size_t)> init(
1133 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1135 detail::read_until_match_op<AsyncReadStream, Allocator,
1136 MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1137 void (boost::system::error_code, std::size_t))>(
1138 s, b, match_condition, init.handler)(
1139 boost::system::error_code(), 0, 1);
1141 return init.result.get();
1145 } // namespace boost
1147 #include <boost/asio/detail/pop_options.hpp>
1149 #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP