1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_oct_stream_h)
27 #define octave_oct_stream_h 1
28 
29 #include "octave-config.h"
30 
31 #include <ios>
32 #include <iosfwd>
33 #include <list>
34 #include <map>
35 #include <memory>
36 #include <string>
37 
38 // These only appear as reference arguments or return values.
39 
40 template <typename T> class Array;
41 class Cell;
42 class octave_value;
43 class octave_value_list;
44 class string_vector;
45 
46 #include "data-conv.h"
47 #include "mach-info.h"
48 
49 namespace octave
50 {
51   class interpreter;
52 
53   // These are only needed as arguments to private functions, so they
54   // are also treated as private.
55 
56   class scanf_format_elt;
57   class scanf_format_list;
58 
59   class printf_format_elt;
60   class printf_format_list;
61 
62   // Provide an interface for Octave streams.
63 
64   class
65   OCTINTERP_API
66   base_stream
67   {
68     friend class stream;
69 
70   public:
71 
72     base_stream (std::ios::openmode arg_md = std::ios::in | std::ios::out,
73                  mach_info::float_format ff = mach_info::native_float_format (),
74                  const std::string& encoding = "utf-8")
m_mode(arg_md)75       : m_mode (arg_md), m_flt_fmt (ff), m_encoding (encoding),
76         m_fail (false), m_open_state (true), m_errmsg ()
77     { }
78 
79     // No copying!
80 
81     base_stream (const base_stream&) = delete;
82 
83     base_stream& operator = (const base_stream&) = delete;
84 
85     virtual ~base_stream (void) = default;
86 
87     // The remaining functions are not specific to input or output only,
88     // and must be provided by the derived classes.
89 
90     // Position a stream at OFFSET relative to ORIGIN.
91 
92     virtual int seek (off_t offset, int origin) = 0;
93 
94     // Return current stream position.
95 
96     virtual off_t tell (void) = 0;
97 
98     // Return TRUE if EOF has been reached on this stream.
99 
100     virtual bool eof (void) const = 0;
101 
102     // The name of the file.
103 
104     virtual std::string name (void) const = 0;
105 
106     // If the derived class provides this function and it returns a
107     // pointer to a valid istream, scanf(), read(), getl(), and gets()
108     // will automatically work for this stream.
109 
input_stream(void)110     virtual std::istream * input_stream (void) { return nullptr; }
111 
112     // If the derived class provides this function and it returns a
113     // pointer to a valid ostream, flush(), write(), and printf() will
114     // automatically work for this stream.
115 
output_stream(void)116     virtual std::ostream * output_stream (void) { return nullptr; }
117 
118     // Return TRUE if this stream is open.
119 
is_open(void)120     bool is_open (void) const { return m_open_state; }
121 
do_close(void)122     virtual void do_close (void) { }
123 
close(void)124     void close (void)
125     {
126       if (is_open ())
127         {
128           m_open_state = false;
129           do_close ();
130         }
131     }
132 
file_number(void)133     virtual int file_number (void) const
134     {
135       // Kluge alert!
136 
137       if (name () == "stdin")
138         return 0;
139       else if (name () == "stdout")
140         return 1;
141       else if (name () == "stderr")
142         return 2;
143       else
144         return -1;
145     }
146 
ok(void)147     bool ok (void) const { return ! m_fail; }
148 
149     // Return current error message for this stream.
150 
151     std::string error (bool clear, int& err_num);
152 
153   protected:
154 
mode(void)155     int mode (void) const { return m_mode; }
156 
float_format(void)157     mach_info::float_format float_format (void) const { return m_flt_fmt; }
158 
encoding(void)159     std::string encoding (void) const { return m_encoding; }
160 
161     // Set current error state and set fail to TRUE.
162 
163     void error (const std::string& msg);
164     void error (const std::string& who, const std::string& msg);
165 
166     // Clear any error message and set fail to FALSE.
167 
168     void clear (void);
169 
170     // Clear stream state.
171 
172     void clearerr (void);
173 
174   private:
175 
176     // The permission bits for the file.  Should be some combination of
177     // std::ios::open_mode bits.
178     int m_mode;
179 
180     // Data format.
181     mach_info::float_format m_flt_fmt;
182 
183     // Code page
184     std::string m_encoding;
185 
186     // TRUE if an error has occurred.
187     bool m_fail;
188 
189     // TRUE if this stream is open.
190     bool m_open_state;
191 
192     // Should contain error message if fail is TRUE.
193     std::string m_errmsg;
194 
195     // Functions that are defined for all input streams (input streams
196     // are those that define is).
197 
198     std::string do_gets (octave_idx_type max_len, bool& err, bool strip_newline,
199                          const std::string& who /* = "gets" */);
200 
201     std::string getl (octave_idx_type max_len, bool& err,
202                       const std::string& who /* = "getl" */);
203     std::string gets (octave_idx_type max_len, bool& err,
204                       const std::string& who /* = "gets" */);
205     off_t skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
206 
207     octave_value do_scanf (scanf_format_list& fmt_list, octave_idx_type nr,
208                            octave_idx_type nc,
209                            bool one_elt_size_spec, octave_idx_type& count,
210                            const std::string& who /* = "scanf" */);
211 
212     octave_value scanf (const std::string& fmt, const Array<double>& size,
213                         octave_idx_type& count, const std::string& who /* = "scanf" */);
214 
215     bool do_oscanf (const scanf_format_elt *elt, octave_value&,
216                     const std::string& who /* = "scanf" */);
217 
218     octave_value_list oscanf (const std::string& fmt,
219                               const std::string& who /* = "scanf" */);
220 
221     octave_value do_textscan (const std::string& fmt, octave_idx_type ntimes,
222                               const octave_value_list& options,
223                               const std::string& who, octave_idx_type& count);
224 
225     // Functions that are defined for all output streams (output streams
226     // are those that define os).
227 
228     int flush (void);
229 
230     int do_numeric_printf_conv (std::ostream& os, const printf_format_elt *elt,
231                                 int nsa, int sa_1, int sa_2,
232                                 const octave_value& val,
233                                 const std::string& who);
234 
235     void field_width_error (const std::string& who) const;
236 
237     int do_printf (printf_format_list& fmt_list, const octave_value_list& args,
238                    const std::string& who /* = "printf" */);
239 
240     int printf (const std::string& fmt, const octave_value_list& args,
241                 const std::string& who /* = "printf" */);
242 
243     int puts (const std::string& s, const std::string& who /* = "puts" */);
244 
245     // We can always do this in terms of seek(), so the derived class
246     // only has to provide that.
247 
248     void invalid_operation (const std::string& who, const char *rw);
249   };
250 
251   class
252   OCTINTERP_API
253   stream
254   {
255   public:
256 
257     // BS must be allocated with new or nullptr.
m_rep(bs)258     stream (base_stream *bs = nullptr) : m_rep (bs) { }
259 
260     stream (const stream&) = default;
261 
262     stream& operator = (const stream&) = default;
263 
264     ~stream (void) = default;
265 
266     int flush (void);
267 
268     std::string getl (octave_idx_type max_len, bool& err,
269                       const std::string& who /* = "getl" */);
270     std::string getl (const octave_value& max_len, bool& err,
271                       const std::string& who /* = "getl" */);
272 
273     std::string gets (octave_idx_type max_len, bool& err,
274                       const std::string& who /* = "gets" */);
275     std::string gets (const octave_value& max_len, bool& err,
276                       const std::string& who /* = "gets" */);
277 
278     off_t skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
279     off_t skipl (const octave_value& count, bool& err,
280                  const std::string& who /* = "skipl" */);
281 
282     int seek (off_t offset, int origin);
283     int seek (const octave_value& offset, const octave_value& origin);
284 
285     off_t tell (void);
286 
287     int rewind (void);
288 
289     bool is_open (void) const;
290 
291     void close (void);
292 
293     octave_value read (const Array<double>& size, octave_idx_type block_size,
294                        oct_data_conv::data_type input_type,
295                        oct_data_conv::data_type output_type,
296                        octave_idx_type skip, mach_info::float_format flt_fmt,
297                        octave_idx_type& count);
298 
299     octave_idx_type write (const octave_value& data, octave_idx_type block_size,
300                            oct_data_conv::data_type output_type,
301                            octave_idx_type skip,
302                            mach_info::float_format flt_fmt);
303 
304     bool write_bytes (const void *data, std::size_t n_elts);
305 
306     bool skip_bytes (std::size_t n_elts);
307 
308     template <typename T>
309       octave_idx_type write (const Array<T>& data, octave_idx_type block_size,
310                              oct_data_conv::data_type output_type,
311                              octave_idx_type skip,
312                              mach_info::float_format flt_fmt);
313 
314     octave_value scanf (const std::string& fmt, const Array<double>& size,
315                         octave_idx_type& count, const std::string& who /* = "scanf" */);
316 
317     octave_value scanf (const octave_value& fmt, const Array<double>& size,
318                         octave_idx_type& count, const std::string& who /* = "scanf" */);
319 
320     octave_value_list oscanf (const std::string& fmt,
321                               const std::string& who /* = "scanf" */);
322 
323     octave_value_list oscanf (const octave_value& fmt,
324                               const std::string& who /* = "scanf" */);
325 
326     octave_value textscan (const std::string& fmt, octave_idx_type ntimes,
327                            const octave_value_list& options,
328                            const std::string& who, octave_idx_type& count);
329 
330     int printf (const std::string& fmt, const octave_value_list& args,
331                 const std::string& who /* = "printf" */);
332 
333     int printf (const octave_value& fmt, const octave_value_list& args,
334                 const std::string& who /* = "printf" */);
335 
336     int puts (const std::string& s, const std::string& who /* = "puts" */);
337     int puts (const octave_value& s, const std::string& who /* = "puts" */);
338 
339     bool eof (void) const;
340 
341     std::string error (bool clear, int& err_num);
342 
343     std::string error (bool clear = false)
344     {
345       int err_num;
346       return error (clear, err_num);
347     }
348 
349     // Set the error message and state.
350 
error(const std::string & msg)351     void error (const std::string& msg)
352     {
353       if (m_rep)
354         m_rep->error (msg);
355     }
356 
error(const char * msg)357     void error (const char *msg) { error (std::string (msg)); }
358 
file_number(void)359     int file_number (void) { return m_rep ? m_rep->file_number () : -1; }
360 
is_valid(void)361     bool is_valid (void) const { return bool (m_rep); }
362 
ok(void)363     bool ok (void) const { return m_rep && m_rep->ok (); }
364 
365     operator bool () const { return ok (); }
366 
367     std::string name (void) const;
368 
369     int mode (void) const;
370 
371     mach_info::float_format float_format (void) const;
372 
373     static std::string mode_as_string (int mode);
374 
encoding(void)375     std::string encoding (void)
376     {
377       return m_rep ? m_rep->encoding () : std::string ();
378     }
379 
input_stream(void)380     std::istream * input_stream (void)
381     {
382       return m_rep ? m_rep->input_stream () : nullptr;
383     }
384 
output_stream(void)385     std::ostream * output_stream (void)
386     {
387       return m_rep ? m_rep->output_stream () : nullptr;
388     }
389 
clearerr(void)390     void clearerr (void) { if (m_rep) m_rep->clearerr (); }
391 
392   private:
393 
394     // The actual representation of this stream.
395     std::shared_ptr<base_stream> m_rep;
396 
397     bool stream_ok (bool clear = true) const
398     {
399       bool retval = true;
400 
401       if (m_rep)
402         {
403           if (clear)
404             m_rep->clear ();
405         }
406       else
407         retval = false;
408 
409       return retval;
410     }
411 
invalid_operation(const std::string & who,const char * rw)412     void invalid_operation (const std::string& who, const char *rw)
413     {
414       if (m_rep)
415         m_rep->invalid_operation (who, rw);
416     }
417 
418     octave_value
419     finalize_read (std::list<void *>& input_buf_list,
420                    octave_idx_type input_buf_elts,
421                    octave_idx_type elts_read,
422                    octave_idx_type nr, octave_idx_type nc,
423                    oct_data_conv::data_type input_type,
424                    oct_data_conv::data_type output_type,
425                    mach_info::float_format ffmt);
426   };
427 
428   class
429   OCTINTERP_API
430   stream_list
431   {
432   public:
433 
434     stream_list (interpreter& interp);
435 
436     stream_list (const stream_list&) = delete;
437     stream_list& operator = (const stream_list&) = delete;
438 
439     ~stream_list (void);
440 
441     int insert (stream& os);
442 
443     stream lookup (int fid, const std::string& who = "") const;
444     stream lookup (const octave_value& fid, const std::string& who = "") const;
445 
446     int remove (int fid, const std::string& who = "");
447     int remove (const octave_value& fid, const std::string& who = "");
448 
449     void clear (bool flush = true);
450 
451     string_vector get_info (int fid) const;
452     string_vector get_info (const octave_value& fid) const;
453 
454     std::string list_open_files (void) const;
455 
456     octave_value open_file_numbers (void) const;
457 
458     int get_file_number (const octave_value& fid) const;
459 
460     octave_value stdin_file (void) const;
461     octave_value stdout_file (void) const;
462     octave_value stderr_file (void) const;
463 
464   private:
465 
466     typedef std::map<int, stream> ostrl_map;
467 
468     ostrl_map m_list;
469 
470     mutable ostrl_map::const_iterator m_lookup_cache;
471 
472     int m_stdin_file;
473     int m_stdout_file;
474     int m_stderr_file;
475   };
476 }
477 
478 #endif
479