/Src/Dependencies/Boost/boost/iostreams/filter/newline.hpp

http://hadesmem.googlecode.com/ · C++ Header · 442 lines · 352 code · 69 blank · 21 comment · 106 complexity · bf500d3266192679c511606020794e25 MD5 · raw file

  1. // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
  2. // (C) Copyright 2003-2007 Jonathan Turkanis
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
  5. // See http://www.boost.org/libs/iostreams for documentation.
  6. // NOTE: I hope to replace the current implementation with a much simpler
  7. // one.
  8. #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
  9. #define BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
  10. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  11. # pragma once
  12. #endif
  13. #include <boost/assert.hpp>
  14. #include <cstdio>
  15. #include <stdexcept> // logic_error.
  16. #include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
  17. #include <boost/iostreams/categories.hpp>
  18. #include <boost/iostreams/detail/char_traits.hpp>
  19. #include <boost/iostreams/detail/ios.hpp> // BOOST_IOSTREAMS_FAILURE
  20. #include <boost/iostreams/read.hpp> // get
  21. #include <boost/iostreams/write.hpp> // put
  22. #include <boost/iostreams/pipeline.hpp>
  23. #include <boost/iostreams/putback.hpp>
  24. #include <boost/mpl/bool.hpp>
  25. #include <boost/throw_exception.hpp>
  26. #include <boost/type_traits/is_convertible.hpp>
  27. // Must come last.
  28. #include <boost/iostreams/detail/config/disable_warnings.hpp>
  29. #define BOOST_IOSTREAMS_ASSERT_UNREACHABLE(val) \
  30. (BOOST_ASSERT("unreachable code" == 0), val) \
  31. /**/
  32. namespace boost { namespace iostreams {
  33. namespace newline {
  34. const char CR = 0x0D;
  35. const char LF = 0x0A;
  36. // Flags for configuring newline_filter.
  37. // Exactly one of the following three flags must be present.
  38. const int posix = 1; // Use CR as line separator.
  39. const int mac = 2; // Use LF as line separator.
  40. const int dos = 4; // Use CRLF as line separator.
  41. const int mixed = 8; // Mixed line endings.
  42. const int final_newline = 16;
  43. const int platform_mask = posix | dos | mac;
  44. } // End namespace newline.
  45. namespace detail {
  46. class newline_base {
  47. public:
  48. bool is_posix() const
  49. {
  50. return !is_mixed() && (flags_ & newline::posix) != 0;
  51. }
  52. bool is_dos() const
  53. {
  54. return !is_mixed() && (flags_ & newline::dos) != 0;
  55. }
  56. bool is_mac() const
  57. {
  58. return !is_mixed() && (flags_ & newline::mac) != 0;
  59. }
  60. bool is_mixed_posix() const { return (flags_ & newline::posix) != 0; }
  61. bool is_mixed_dos() const { return (flags_ & newline::dos) != 0; }
  62. bool is_mixed_mac() const { return (flags_ & newline::mac) != 0; }
  63. bool is_mixed() const
  64. {
  65. int platform =
  66. (flags_ & newline::posix) != 0 ?
  67. newline::posix :
  68. (flags_ & newline::dos) != 0 ?
  69. newline::dos :
  70. (flags_ & newline::mac) != 0 ?
  71. newline::mac :
  72. 0;
  73. return (flags_ & ~platform & newline::platform_mask) != 0;
  74. }
  75. bool has_final_newline() const
  76. {
  77. return (flags_ & newline::final_newline) != 0;
  78. }
  79. protected:
  80. newline_base(int flags) : flags_(flags) { }
  81. int flags_;
  82. };
  83. } // End namespace detail.
  84. class newline_error
  85. : public BOOST_IOSTREAMS_FAILURE, public detail::newline_base
  86. {
  87. private:
  88. friend class newline_checker;
  89. newline_error(int flags)
  90. : BOOST_IOSTREAMS_FAILURE("bad line endings"),
  91. detail::newline_base(flags)
  92. { }
  93. };
  94. class newline_filter {
  95. public:
  96. typedef char char_type;
  97. struct category
  98. : dual_use,
  99. filter_tag,
  100. closable_tag
  101. { };
  102. explicit newline_filter(int target) : flags_(target)
  103. {
  104. if ( target != iostreams::newline::posix &&
  105. target != iostreams::newline::dos &&
  106. target != iostreams::newline::mac )
  107. {
  108. boost::throw_exception(std::logic_error("bad flags"));
  109. }
  110. }
  111. template<typename Source>
  112. int get(Source& src)
  113. {
  114. using iostreams::newline::CR;
  115. using iostreams::newline::LF;
  116. BOOST_ASSERT((flags_ & f_write) == 0);
  117. flags_ |= f_read;
  118. if (flags_ & (f_has_LF | f_has_EOF)) {
  119. if (flags_ & f_has_LF)
  120. return newline();
  121. else
  122. return EOF;
  123. }
  124. int c =
  125. (flags_ & f_has_CR) == 0 ?
  126. iostreams::get(src) :
  127. CR;
  128. if (c == WOULD_BLOCK )
  129. return WOULD_BLOCK;
  130. if (c == CR) {
  131. flags_ |= f_has_CR;
  132. int d;
  133. if ((d = iostreams::get(src)) == WOULD_BLOCK)
  134. return WOULD_BLOCK;
  135. if (d == LF) {
  136. flags_ &= ~f_has_CR;
  137. return newline();
  138. }
  139. if (d == EOF) {
  140. flags_ |= f_has_EOF;
  141. } else {
  142. iostreams::putback(src, d);
  143. }
  144. flags_ &= ~f_has_CR;
  145. return newline();
  146. }
  147. if (c == LF)
  148. return newline();
  149. return c;
  150. }
  151. template<typename Sink>
  152. bool put(Sink& dest, char c)
  153. {
  154. using iostreams::newline::CR;
  155. using iostreams::newline::LF;
  156. BOOST_ASSERT((flags_ & f_read) == 0);
  157. flags_ |= f_write;
  158. if ((flags_ & f_has_LF) != 0)
  159. return c == LF ?
  160. newline(dest) :
  161. newline(dest) && this->put(dest, c);
  162. if (c == LF)
  163. return newline(dest);
  164. if ((flags_ & f_has_CR) != 0)
  165. return newline(dest) ?
  166. this->put(dest, c) :
  167. false;
  168. if (c == CR) {
  169. flags_ |= f_has_CR;
  170. return true;
  171. }
  172. return iostreams::put(dest, c);
  173. }
  174. template<typename Sink>
  175. void close(Sink& dest, BOOST_IOS::openmode)
  176. {
  177. typedef typename iostreams::category_of<Sink>::type category;
  178. if ((flags_ & f_write) != 0 && (flags_ & f_has_CR) != 0)
  179. newline_if_sink(dest);
  180. flags_ &= ~f_has_LF; // Restore original flags.
  181. }
  182. private:
  183. // Returns the appropriate element of a newline sequence.
  184. int newline()
  185. {
  186. using iostreams::newline::CR;
  187. using iostreams::newline::LF;
  188. switch (flags_ & iostreams::newline::platform_mask) {
  189. case iostreams::newline::posix:
  190. return LF;
  191. case iostreams::newline::mac:
  192. return CR;
  193. case iostreams::newline::dos:
  194. if (flags_ & f_has_LF) {
  195. flags_ &= ~f_has_LF;
  196. return LF;
  197. } else {
  198. flags_ |= f_has_LF;
  199. return CR;
  200. }
  201. }
  202. return BOOST_IOSTREAMS_ASSERT_UNREACHABLE(0);
  203. }
  204. // Writes a newline sequence.
  205. template<typename Sink>
  206. bool newline(Sink& dest)
  207. {
  208. using iostreams::newline::CR;
  209. using iostreams::newline::LF;
  210. bool success = false;
  211. switch (flags_ & iostreams::newline::platform_mask) {
  212. case iostreams::newline::posix:
  213. success = boost::iostreams::put(dest, LF);
  214. break;
  215. case iostreams::newline::mac:
  216. success = boost::iostreams::put(dest, CR);
  217. break;
  218. case iostreams::newline::dos:
  219. if ((flags_ & f_has_LF) != 0) {
  220. if ((success = boost::iostreams::put(dest, LF)))
  221. flags_ &= ~f_has_LF;
  222. } else if (boost::iostreams::put(dest, CR)) {
  223. if (!(success = boost::iostreams::put(dest, LF)))
  224. flags_ |= f_has_LF;
  225. }
  226. break;
  227. }
  228. if (success)
  229. flags_ &= ~f_has_CR;
  230. return success;
  231. }
  232. // Writes a newline sequence if the given device is a Sink.
  233. template<typename Device>
  234. void newline_if_sink(Device& dest)
  235. {
  236. typedef typename iostreams::category_of<Device>::type category;
  237. newline_if_sink(dest, is_convertible<category, output>());
  238. }
  239. template<typename Sink>
  240. void newline_if_sink(Sink& dest, mpl::true_) { newline(dest); }
  241. template<typename Source>
  242. void newline_if_sink(Source&, mpl::false_) { }
  243. enum flags {
  244. f_has_LF = 32768,
  245. f_has_CR = f_has_LF << 1,
  246. f_has_newline = f_has_CR << 1,
  247. f_has_EOF = f_has_newline << 1,
  248. f_read = f_has_EOF << 1,
  249. f_write = f_read << 1
  250. };
  251. int flags_;
  252. };
  253. BOOST_IOSTREAMS_PIPABLE(newline_filter, 0)
  254. class newline_checker : public detail::newline_base {
  255. public:
  256. typedef char char_type;
  257. struct category
  258. : dual_use_filter_tag,
  259. closable_tag
  260. { };
  261. explicit newline_checker(int target = newline::mixed)
  262. : detail::newline_base(0), target_(target), open_(false)
  263. { }
  264. template<typename Source>
  265. int get(Source& src)
  266. {
  267. using newline::CR;
  268. using newline::LF;
  269. if (!open_) {
  270. open_ = true;
  271. source() = 0;
  272. }
  273. int c;
  274. if ((c = iostreams::get(src)) == WOULD_BLOCK)
  275. return WOULD_BLOCK;
  276. // Update source flags.
  277. if (c != EOF)
  278. source() &= ~f_line_complete;
  279. if ((source() & f_has_CR) != 0) {
  280. if (c == LF) {
  281. source() |= newline::dos;
  282. source() |= f_line_complete;
  283. } else {
  284. source() |= newline::mac;
  285. if (c == EOF)
  286. source() |= f_line_complete;
  287. }
  288. } else if (c == LF) {
  289. source() |= newline::posix;
  290. source() |= f_line_complete;
  291. }
  292. source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
  293. // Check for errors.
  294. if ( c == EOF &&
  295. (target_ & newline::final_newline) != 0 &&
  296. (source() & f_line_complete) == 0 )
  297. {
  298. fail();
  299. }
  300. if ( (target_ & newline::platform_mask) != 0 &&
  301. (source() & ~target_ & newline::platform_mask) != 0 )
  302. {
  303. fail();
  304. }
  305. return c;
  306. }
  307. template<typename Sink>
  308. bool put(Sink& dest, int c)
  309. {
  310. using iostreams::newline::CR;
  311. using iostreams::newline::LF;
  312. if (!open_) {
  313. open_ = true;
  314. source() = 0;
  315. }
  316. if (!iostreams::put(dest, c))
  317. return false;
  318. // Update source flags.
  319. source() &= ~f_line_complete;
  320. if ((source() & f_has_CR) != 0) {
  321. if (c == LF) {
  322. source() |= newline::dos;
  323. source() |= f_line_complete;
  324. } else {
  325. source() |= newline::mac;
  326. }
  327. } else if (c == LF) {
  328. source() |= newline::posix;
  329. source() |= f_line_complete;
  330. }
  331. source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
  332. // Check for errors.
  333. if ( (target_ & newline::platform_mask) != 0 &&
  334. (source() & ~target_ & newline::platform_mask) != 0 )
  335. {
  336. fail();
  337. }
  338. return true;
  339. }
  340. template<typename Sink>
  341. void close(Sink&, BOOST_IOS::openmode)
  342. {
  343. using iostreams::newline::final_newline;
  344. // Update final_newline flag.
  345. if ( (source() & f_has_CR) != 0 ||
  346. (source() & f_line_complete) != 0 )
  347. {
  348. source() |= final_newline;
  349. }
  350. // Clear non-sticky flags.
  351. source() &= ~(f_has_CR | f_line_complete);
  352. // Check for errors.
  353. if ( (target_ & final_newline) != 0 &&
  354. (source() & final_newline) == 0 )
  355. {
  356. fail();
  357. }
  358. }
  359. private:
  360. void fail() { boost::throw_exception(newline_error(source())); }
  361. int& source() { return flags_; }
  362. int source() const { return flags_; }
  363. enum flags {
  364. f_has_CR = 32768,
  365. f_line_complete = f_has_CR << 1
  366. };
  367. int target_; // Represents expected input.
  368. bool open_;
  369. };
  370. BOOST_IOSTREAMS_PIPABLE(newline_checker, 0)
  371. } } // End namespaces iostreams, boost.
  372. #include <boost/iostreams/detail/config/enable_warnings.hpp>
  373. #endif // #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED