source: mainline/uspace/lib/cpp/include/__bits/io/fstream.hpp@ 8fd0675f

Last change on this file since 8fd0675f was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 21.0 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_IO_FSTREAM
8#define LIBCPP_BITS_IO_FSTREAM
9
10#include <cassert>
11#include <cstdio>
12#include <ios>
13#include <iosfwd>
14#include <locale>
15#include <streambuf>
16#include <string>
17
18namespace std
19{
20 /**
21 * 27.9.1.1, class template basic_filebuf:
22 */
23 template<class Char, class Traits>
24 class basic_filebuf: public basic_streambuf<Char, Traits>
25 {
26 public:
27 using char_type = Char;
28 using traits_type = Traits;
29 using int_type = typename traits_type::int_type;
30 using pos_type = typename traits_type::pos_type;
31 using off_type = typename traits_type::off_type;
32
33 /**
34 * 27.9.1.2, constructors/destructor:
35 */
36
37 basic_filebuf()
38 : basic_streambuf<char_type, traits_type>{},
39 obuf_{nullptr}, ibuf_{nullptr}, mode_{}, file_{nullptr}
40 { /* DUMMY BODY */ }
41
42 basic_filebuf(const basic_filebuf&) = delete;
43
44 basic_filebuf(basic_filebuf&& other)
45 : mode_{other.mode_}
46 {
47 close();
48 std::swap(obuf_, other.obuf_);
49 std::swap(ibuf_, other.ibuf_);
50 std::swap(file_, other.file_);
51
52 basic_streambuf<char_type, traits_type>::swap(other);
53 }
54
55 virtual ~basic_filebuf()
56 {
57 // TODO: exception here caught and not rethrown
58 close();
59 }
60
61 /**
62 * 27.9.1.3: assign/swap:
63 */
64
65 basic_filebuf& operator=(const basic_filebuf&) = delete;
66
67 basic_filebuf& operator=(basic_filebuf&& other)
68 {
69 close();
70 swap(other);
71
72 return *this;
73 }
74
75 void swap(basic_filebuf& rhs)
76 {
77 std::swap(mode_, rhs.mode_);
78 std::swap(obuf_, rhs.obuf_);
79 std::swap(ibuf_, rhs.ibuf_);
80
81 basic_streambuf<char_type, traits_type>::swap(rhs);
82 }
83
84 /**
85 * 27.9.1.4, members:
86 */
87
88 bool is_open() const
89 {
90 return file_ != nullptr;
91 }
92
93 basic_filebuf<char_type, traits_type>* open(const char* name, ios_base::openmode mode)
94 {
95 if (file_)
96 return nullptr;
97
98 mode_ = mode;
99 mode = (mode & (~ios_base::ate));
100 const char* mode_str = get_mode_str_(mode);
101
102 if (!mode_str)
103 return nullptr;
104
105 file_ = fopen(name, mode_str);
106 if (!file_)
107 return nullptr;
108
109 if ((mode_ & ios_base::ate) != 0)
110 {
111 if (fseek(file_, 0, SEEK_END) != 0)
112 {
113 close();
114 return nullptr;
115 }
116 }
117
118 if (!ibuf_ && mode_is_in_(mode_))
119 ibuf_ = new char_type[buf_size_];
120 if (!obuf_ && mode_is_out_(mode_))
121 obuf_ = new char_type[buf_size_];
122 init_();
123
124 return this;
125 }
126
127 basic_filebuf<char_type, traits_type>* open(const string& name, ios_base::openmode mode)
128 {
129 return open(name.c_str(), mode);
130 }
131
132 basic_filebuf<char_type, traits_type>* close()
133 {
134 // TODO: caught exceptions are to be rethrown after closing the file
135 if (!file_)
136 return nullptr;
137 // TODO: deallocate buffers?
138
139 if (this->output_next_ != this->output_begin_)
140 overflow(traits_type::eof());
141 // TODO: unshift? (p. 1084 at the top)
142
143 fclose(file_);
144 file_ = nullptr;
145
146 return this;
147 }
148
149 protected:
150 /**
151 * 27.9.1.5, overriden virtual functions:
152 */
153
154 int_type underflow() override
155 {
156 // TODO: use codecvt
157 if (!mode_is_in_(mode_))
158 return traits_type::eof();
159
160 if (!ibuf_)
161 {
162 ibuf_ = new char_type[buf_size_];
163 this->input_begin_ = this->input_next_ = this->input_end_ = ibuf_;
164 }
165
166 off_type i{};
167 if (this->input_next_ < this->input_end_)
168 {
169 auto idx = static_cast<off_type>(this->input_next_ - this->input_begin_);
170 auto count = static_cast<off_type>(buf_size_) - idx;
171
172 for (; i < count; ++i, ++idx)
173 ibuf_[i] = ibuf_[idx];
174 }
175
176 for (; i < static_cast<off_type>(buf_size_); ++i)
177 {
178 auto c = fgetc(file_);
179 if (c == traits_type::eof())
180 break;
181
182 ibuf_[i] = static_cast<char_type>(c);
183
184 if (ibuf_[i] == '\n')
185 {
186 ++i;
187 break;
188 }
189 }
190
191 this->input_next_ = this->input_begin_;
192 this->input_end_ = this->input_begin_ + i;
193
194 if (i == 0)
195 return traits_type::eof();
196
197 return traits_type::to_int_type(*this->input_next_);
198 }
199
200 int_type pbackfail(int_type c = traits_type::eof()) override
201 {
202 auto cc = traits_type::to_char_type(c);
203 if (!traits_type::eq_int_type(c, traits_type::eof()) &&
204 this->putback_avail_() &&
205 traits_type::eq(cc, this->gptr()[-1]))
206 {
207 --this->input_next_;
208
209 return c;
210 }
211 else if (!traits_type::eq_int_type(c, traits_type::eof()) &&
212 this->putback_avail_() && (mode_ & ios_base::out) != 0)
213 {
214 *--this->input_next_ = cc;
215
216 return c;
217 }
218 else if (traits_type::eq_int_type(c, traits_type::eof()) &&
219 this->putback_avail_())
220 {
221 --this->input_next_;
222
223 return traits_type::not_eof(c);
224 }
225
226 return traits_type::eof();
227 }
228
229 int_type overflow(int_type c = traits_type::eof()) override
230 {
231 // TODO: use codecvt
232 if (!mode_is_out_(mode_))
233 return traits_type::eof();
234
235 auto count = static_cast<size_t>(this->output_next_ - this->output_begin_);
236 fwrite(obuf_, sizeof(char_type), count, file_);
237 fflush(file_);
238
239 this->output_next_ = this->output_begin_;
240
241 return traits_type::not_eof(c);
242 }
243
244 basic_streambuf<char_type, traits_type>*
245 setbuf(char_type* s, streamsize n) override
246 {
247 // TODO: implement
248 __unimplemented();
249 return nullptr;
250 }
251
252 pos_type seekoff(off_type off, ios_base::seekdir dir,
253 ios_base::openmode mode = ios_base::in | ios_base::out) override
254 {
255 // TODO: implement
256 __unimplemented();
257 return pos_type{};
258 }
259
260 pos_type seekpos(pos_type pos,
261 ios_base::openmode mode = ios_base::in | ios_base::out) override
262 {
263 // TODO: implement
264 __unimplemented();
265 return pos_type{};
266 }
267
268 int sync() override
269 {
270 if (mode_is_out_(mode_))
271 overflow();
272
273 return 0; // TODO: what is the correct return value?
274 }
275
276 void imbue(const locale& loc) override
277 {
278 // TODO: codecvt should be cached when we start using it
279 basic_streambuf<char_type, traits_type>::imbue(loc);
280 }
281
282 private:
283 char_type* obuf_;
284 char_type* ibuf_;
285
286 ios_base::openmode mode_;
287
288 FILE* file_;
289
290 static constexpr size_t buf_size_{128};
291
292 const char* get_mode_str_(ios_base::openmode mode)
293 {
294 /**
295 * See table 132.
296 */
297 switch (mode)
298 {
299 case ios_base::out:
300 case ios_base::out | ios_base::trunc:
301 return "w";
302 case ios_base::out | ios_base::app:
303 case ios_base::app:
304 return "a";
305 case ios_base::in:
306 return "r";
307 case ios_base::in | ios_base::out:
308 return "r+";
309 case ios_base::in | ios_base::out | ios_base::trunc:
310 return "w+";
311 case ios_base::in | ios_base::out | ios_base::app:
312 case ios_base::in | ios_base::app:
313 return "a+";
314 case ios_base::binary | ios_base::out:
315 case ios_base::binary | ios_base::out | ios_base::trunc:
316 return "wb";
317 case ios_base::binary | ios_base::out | ios_base::app:
318 case ios_base::binary | ios_base::app:
319 return "ab";
320 case ios_base::binary | ios_base::in:
321 return "rb";
322 case ios_base::binary | ios_base::in | ios_base::out:
323 return "r+b";
324 case ios_base::binary | ios_base::in | ios_base::out | ios_base::trunc:
325 return "w+b";
326 case ios_base::binary | ios_base::in | ios_base::out | ios_base::app:
327 case ios_base::binary | ios_base::in | ios_base::app:
328 return "a+b";
329 default:
330 return nullptr;
331 }
332 }
333
334 bool mode_is_in_(ios_base::openmode mode)
335 {
336 return (mode & ios_base::in) != 0;
337 }
338
339 bool mode_is_out_(ios_base::openmode mode)
340 {
341 return (mode & (ios_base::out | ios_base::app | ios_base::trunc)) != 0;
342 }
343
344 void init_()
345 {
346 if (ibuf_)
347 this->input_begin_ = this->input_next_ = this->input_end_ = ibuf_;
348
349 if (obuf_)
350 {
351 this->output_begin_ = this->output_next_ = obuf_;
352 this->output_end_ = obuf_ + buf_size_;
353 }
354 }
355 };
356
357 template<class Char, class Traits>
358 void swap(basic_filebuf<Char, Traits>& lhs, basic_filebuf<Char, Traits>& rhs)
359 {
360 lhs.swap(rhs);
361 }
362
363 /**
364 * 27.9.1.6, class template basic_ifstream:
365 */
366
367 template<class Char, class Traits>
368 class basic_ifstream: public basic_istream<Char, Traits>
369 {
370 public:
371 using char_type = Char;
372 using traits_type = Traits;
373 using int_type = typename traits_type::int_type;
374 using pos_type = typename traits_type::pos_type;
375 using off_type = typename traits_type::off_type;
376
377 /**
378 * 27.9.1.7, constructors:
379 */
380
381 basic_ifstream()
382 : basic_istream<char_type, traits_type>{&rdbuf_},
383 rdbuf_{}
384 { /* DUMMY BODY */ }
385
386 explicit basic_ifstream(const char* name, ios_base::openmode mode = ios_base::in)
387 : basic_istream<char_type, traits_type>{&rdbuf_},
388 rdbuf_{}
389 {
390 if (!rdbuf_.open(name, mode | ios_base::in))
391 this->setstate(ios_base::failbit);
392 }
393
394 explicit basic_ifstream(const string& name, ios_base::openmode mode = ios_base::in)
395 : basic_istream<char_type, traits_type>{&rdbuf_},
396 rdbuf_{}
397 {
398 if (!rdbuf_.open(name, mode | ios_base::in))
399 this->setstate(ios_base::failbit);
400 }
401
402 basic_ifstream(const basic_ifstream&) = delete;
403
404 basic_ifstream(basic_ifstream&& other)
405 : basic_istream<char_type, traits_type>{move(other)},
406 rdbuf_{other.rdbuf_}
407 {
408 basic_istream<char_type, traits_type>::set_rdbuf(&rdbuf_);
409 }
410
411 /**
412 * 27.9.1.8, assign/swap:
413 */
414
415 basic_ifstream& operator=(const basic_ifstream&) = delete;
416
417 basic_ifstream& operator=(basic_ifstream&& other)
418 {
419 swap(other);
420 }
421
422 void swap(basic_ifstream& rhs)
423 {
424 basic_istream<char_type, traits_type>::swap(rhs);
425 rdbuf_.swap(rhs.rdbuf_);
426 }
427
428 /**
429 * 27.9.1.9, members:
430 */
431
432 basic_filebuf<char_type, traits_type>* rdbuf() const
433 {
434 return const_cast<basic_filebuf<char_type, traits_type>*>(&rdbuf_);
435 }
436
437 bool is_open() const
438 {
439 return rdbuf_.is_open();
440 }
441
442 void open(const char* name, ios_base::openmode mode = ios_base::in)
443 {
444 if (!rdbuf_.open(name, mode | ios_base::in))
445 this->setstate(ios_base::failbit);
446 else
447 this->clear();
448 }
449
450 void open(const string& name, ios_base::openmode mode = ios_base::in)
451 {
452 open(name.c_str(), mode);
453 }
454
455 void close()
456 {
457 if (!rdbuf_.close())
458 this->setstate(ios_base::failbit);
459 }
460
461 private:
462 basic_filebuf<char_type, traits_type> rdbuf_;
463 };
464
465 template<class Char, class Traits>
466 void swap(basic_ifstream<Char, Traits>& lhs,
467 basic_ifstream<Char, Traits>& rhs)
468 {
469 lhs.swap(rhs);
470 }
471
472 /**
473 * 27.9.1.10, class template basic_ofstream:
474 */
475
476 template<class Char, class Traits>
477 class basic_ofstream: public basic_ostream<Char, Traits>
478 {
479 public:
480 using char_type = Char;
481 using traits_type = Traits;
482 using int_type = typename traits_type::int_type;
483 using pos_type = typename traits_type::pos_type;
484 using off_type = typename traits_type::off_type;
485
486 /**
487 * 27.9.1.11, constructors:
488 */
489
490 basic_ofstream()
491 : basic_ostream<char_type, traits_type>{&rdbuf_},
492 rdbuf_{}
493 { /* DUMMY BODY */ }
494
495 explicit basic_ofstream(const char* name, ios_base::openmode mode = ios_base::out)
496 : basic_ostream<char_type, traits_type>{&rdbuf_},
497 rdbuf_{}
498 {
499 if (!rdbuf_.open(name, mode | ios_base::out))
500 this->setstate(ios_base::failbit);
501 }
502
503 explicit basic_ofstream(const string& name, ios_base::openmode mode = ios_base::out)
504 : basic_ostream<char_type, traits_type>{&rdbuf_},
505 rdbuf_{}
506 {
507 if (!rdbuf_.open(name, mode | ios_base::out))
508 this->setstate(ios_base::failbit);
509 }
510
511 basic_ofstream(const basic_ofstream&) = delete;
512
513 basic_ofstream(basic_ofstream&& other)
514 : basic_ostream<char_type, traits_type>{move(other)},
515 rdbuf_{other.rdbuf_}
516 {
517 basic_ostream<char_type, traits_type>::set_rdbuf(&rdbuf_);
518 }
519
520 /**
521 * 27.9.1.12, assign/swap:
522 */
523
524 basic_ofstream& operator=(const basic_ofstream&) = delete;
525
526 basic_ofstream& operator=(basic_ofstream&& other)
527 {
528 swap(other);
529 }
530
531 void swap(basic_ofstream& rhs)
532 {
533 basic_ostream<char_type, traits_type>::swap(rhs);
534 rdbuf_.swap(rhs.rdbuf_);
535 }
536
537 /**
538 * 27.9.1.13, members:
539 */
540
541 basic_filebuf<char_type, traits_type>* rdbuf() const
542 {
543 return const_cast<basic_filebuf<char_type, traits_type>*>(&rdbuf_);
544 }
545
546 bool is_open() const
547 {
548 return rdbuf_.is_open();
549 }
550
551 void open(const char* name, ios_base::openmode mode = ios_base::out)
552 {
553 if (!rdbuf_.open(name, mode | ios_base::out))
554 this->setstate(ios_base::failbit);
555 else
556 this->clear();
557 }
558
559 void open(const string& name, ios_base::openmode mode = ios_base::out)
560 {
561 open(name.c_str(), mode);
562 }
563
564 void close()
565 {
566 if (!rdbuf_.close())
567 this->setstate(ios_base::failbit);
568 }
569
570 private:
571 basic_filebuf<char_type, traits_type> rdbuf_;
572 };
573
574 template<class Char, class Traits>
575 void swap(basic_ofstream<Char, Traits>& lhs,
576 basic_ofstream<Char, Traits>& rhs)
577 {
578 lhs.swap(rhs);
579 }
580
581 /**
582 * 27.9.1.14, class template basic_fstream:
583 */
584
585 template<class Char, class Traits>
586 class basic_fstream: public basic_iostream<Char, Traits>
587 {
588 public:
589 using char_type = Char;
590 using traits_type = Traits;
591 using int_type = typename traits_type::int_type;
592 using pos_type = typename traits_type::pos_type;
593 using off_type = typename traits_type::off_type;
594
595 /**
596 * 27.9.1.15, constructors:
597 */
598
599 basic_fstream()
600 : basic_iostream<char_type, traits_type>{&rdbuf_},
601 rdbuf_{}
602 { /* DUMMY BODY */ }
603
604 explicit basic_fstream(const char* name,
605 ios_base::openmode mode = ios_base::in | ios_base::out)
606 : basic_iostream<char_type, traits_type>{&rdbuf_},
607 rdbuf_{}
608 {
609 if (!rdbuf_.open(name, mode))
610 this->setstate(ios_base::failbit);
611 }
612
613 explicit basic_fstream(const string& name,
614 ios_base::openmode mode = ios_base::in | ios_base::out)
615 : basic_iostream<char_type, traits_type>{&rdbuf_},
616 rdbuf_{}
617 {
618 if (!rdbuf_.open(name, mode))
619 this->setstate(ios_base::failbit);
620 }
621
622 basic_fstream(const basic_fstream&) = delete;
623
624 basic_fstream(basic_fstream&& other)
625 : basic_iostream<char_type, traits_type>{move(other)},
626 rdbuf_{other.rdbuf_}
627 {
628 basic_iostream<char_type, traits_type>::set_rdbuf(&rdbuf_);
629 }
630
631 /**
632 * 27.9.1.16, assign/swap:
633 */
634
635 basic_fstream& operator=(const basic_fstream&) = delete;
636
637 basic_fstream& operator=(basic_fstream&& other)
638 {
639 swap(other);
640 }
641
642 void swap(basic_fstream& rhs)
643 {
644 basic_iostream<char_type, traits_type>::swap(rhs);
645 rdbuf_.swap(rhs.rdbuf_);
646 }
647
648 /**
649 * 27.9.1.17, members:
650 */
651
652 basic_filebuf<char_type, traits_type>* rdbuf() const
653 {
654 return const_cast<basic_filebuf<char_type, traits_type>*>(&rdbuf_);
655 }
656
657 bool is_open() const
658 {
659 return rdbuf_.is_open();
660 }
661
662 void open(const char* name,
663 ios_base::openmode mode = ios_base::in | ios_base::out)
664 {
665 if (!rdbuf_.open(name, mode))
666 this->setstate(ios_base::failbit);
667 else
668 this->clear();
669 }
670
671 void open(const string& name,
672 ios_base::openmode mode = ios_base::in | ios_base::out)
673 {
674 open(name.c_str(), mode);
675 }
676
677 void close()
678 {
679 if (!rdbuf_.close())
680 this->setstate(ios_base::failbit);
681 }
682
683 private:
684 basic_filebuf<char_type, traits_type> rdbuf_;
685 };
686
687 template<class Char, class Traits>
688 void swap(basic_fstream<Char, Traits>& lhs,
689 basic_fstream<Char, Traits>& rhs)
690 {
691 lhs.swap(rhs);
692 }
693}
694
695#endif
Note: See TracBrowser for help on using the repository browser.