changelog shortlog tags changeset files revisions annotate raw

src/file-io.cc

changeset 10289: 4b124317dc38
parent:2d47356a7a1a
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (34 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
4 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
21
22*/
23
24// Originally written by John C. Campbell <jcc@bevo.che.wisc.edu>
25//
26// Thomas Baier <baier@ci.tuwien.ac.at> added the original versions of
27// the following functions:
28//
29// popen
30// pclose
31// execute (now popen2.m)
32// sync_system (now merged with system)
33// async_system (now merged with system)
34
35// Extensively revised by John W. Eaton <jwe@octave.org>,
36// April 1996.
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41
42#include <cerrno>
43#include <climits>
44#include <cstdio>
45
46#include <iostream>
47#include <stack>
48#include <vector>
49
50#include <sys/types.h>
51#include <unistd.h>
52
53#ifdef HAVE_ZLIB_H
54#include <zlib.h>
55#endif
56
57#include "error.h"
58#include "file-ops.h"
59#include "file-stat.h"
60#include "lo-ieee.h"
61#include "oct-env.h"
62#include "oct-locbuf.h"
63
64#include "defun.h"
65#include "file-io.h"
66#include "load-path.h"
67#include "oct-fstrm.h"
68#include "oct-iostrm.h"
69#include "oct-map.h"
70#include "oct-obj.h"
71#include "oct-prcstrm.h"
72#include "oct-stream.h"
73#include "oct-strstrm.h"
74#include "pager.h"
75#include "sysdep.h"
76#include "utils.h"
77#include "variables.h"
78
79static octave_value stdin_file;
80static octave_value stdout_file;
81static octave_value stderr_file;
82
83static octave_stream stdin_stream;
84static octave_stream stdout_stream;
85static octave_stream stderr_stream;
86
87void
88initialize_file_io (void)
89{
90 stdin_stream = octave_istream::create (&std::cin, "stdin");
91
92 // This uses octave_stdout (see pager.h), not std::cout so that Octave's
93 // standard output stream will pass through the pager.
94
95 stdout_stream = octave_ostream::create (&octave_stdout, "stdout");
96
97 stderr_stream = octave_ostream::create (&std::cerr, "stderr");
98
99 stdin_file = octave_stream_list::insert (stdin_stream);
100 stdout_file = octave_stream_list::insert (stdout_stream);
101 stderr_file = octave_stream_list::insert (stderr_stream);
102}
103
104void
105close_files (void)
106{
107 octave_stream_list::clear ();
108}
109
110// List of files to delete when we exit or crash.
111//
112// FIXME -- this should really be static, but that causes
113// problems on some systems.
114std::stack <std::string> tmp_files;
115
116void
117mark_for_deletion (const std::string& file)
118{
119 tmp_files.push (file);
120}
121
122void
123cleanup_tmp_files (void)
124{
125 while (! tmp_files.empty ())
126 {
127 std::string filename = tmp_files.top ();
128 tmp_files.pop ();
129 unlink (filename.c_str ());
130 }
131}
132
133static std::ios::openmode
134fopen_mode_to_ios_mode (const std::string& mode_arg)
135{
136 std::ios::openmode retval = std::ios::in;
137
138 if (! mode_arg.empty ())
139 {
140 // Could probably be faster, but does it really matter?
141
142 std::string mode = mode_arg;
143
144 // 'W' and 'R' are accepted as 'w' and 'r', but we warn about
145 // them because Matlab says they perform "automatic flushing"
146 // but we don't know precisely what action that implies.
147
148 size_t pos = mode.find ('W');
149
150 if (pos != std::string::npos)
151 {
152 warning ("fopen: treating mode \"W\" as equivalent to \"w\"");
153 mode[pos] = 'w';
154 }
155
156 pos = mode.find ('R');
157
158 if (pos != std::string::npos)
159 {
160 warning ("fopen: treating mode \"R\" as equivalent to \"r\"");
161 mode[pos] = 'r';
162 }
163
164 pos = mode.find ('z');
165
166 if (pos != std::string::npos)
167 {
168#if defined (HAVE_ZLIB)
169 mode.erase (pos, 1);
170#else
171 error ("this version of Octave does not support gzipped files");
172#endif
173 }
174
175 if (! error_state)
176 {
177 if (mode == "rt")
178 retval = std::ios::in;
179 else if (mode == "wt")
180 retval = std::ios::out | std::ios::trunc;
181 else if (mode == "at")
182 retval = std::ios::out | std::ios::app;
183 else if (mode == "r+t" || mode == "rt+")
184 retval = std::ios::in | std::ios::out;
185 else if (mode == "w+t" || mode == "wt+")
186 retval = std::ios::in | std::ios::out | std::ios::trunc;
187 else if (mode == "a+t" || mode == "at+")
188 retval = std::ios::in | std::ios::out | std::ios::app;
189 else if (mode == "rb" || mode == "r")
190 retval = std::ios::in | std::ios::binary;
191 else if (mode == "wb" || mode == "w")
192 retval = std::ios::out | std::ios::trunc | std::ios::binary;
193 else if (mode == "ab" || mode == "a")
194 retval = std::ios::out | std::ios::app | std::ios::binary;
195 else if (mode == "r+b" || mode == "rb+" || mode == "r+")
196 retval = std::ios::in | std::ios::out | std::ios::binary;
197 else if (mode == "w+b" || mode == "wb+" || mode == "w+")
198 retval = (std::ios::in | std::ios::out | std::ios::trunc
199 | std::ios::binary);
200 else if (mode == "a+b" || mode == "ab+" || mode == "a+")
201 retval = (std::ios::in | std::ios::out | std::ios::app
202 | std::ios::binary);
203 else
204 ::error ("invalid mode specified");
205 }
206 }
207
208 return retval;
209}
210
211DEFUN (fclose, args, ,
212 "-*- texinfo -*-\n\
213@deftypefn {Built-in Function} {} fclose (@var{fid})\n\
214Closes the specified file. If successful, @code{fclose} returns 0,\n\
215otherwise, it returns -1.\n\
216@seealso{fopen, fseek, ftell}\n\
217@end deftypefn")
218{
219 octave_value retval = -1;
220
221 int nargin = args.length ();
222
223 if (nargin == 1)
224 retval = octave_stream_list::remove (args(0), "fclose");
225 else
226 print_usage ();
227
228 return retval;
229}
230
231DEFUN (fclear, args, ,
232 "-*- texinfo -*-\n\
233@deftypefn {Built-in Function} {} fclear (@var{fid})\n\
234Clear the stream state for the specified file.\n\
235@end deftypefn")
236{
237 octave_value retval;
238
239 int nargin = args.length ();
240
241 if (nargin == 1)
242 {
243 int fid = octave_stream_list::get_file_number (args (0));
244
245 octave_stream os = octave_stream_list::lookup (fid, "fclear");
246
247 if (! error_state)
248 os.clearerr ();
249 }
250 else
251 print_usage ();
252
253 return retval;
254}
255
256DEFUN (fflush, args, ,
257 "-*- texinfo -*-\n\
258@deftypefn {Built-in Function} {} fflush (@var{fid})\n\
259Flush output to @var{fid}. This is useful for ensuring that all\n\
260pending output makes it to the screen before some other event occurs.\n\
261For example, it is always a good idea to flush the standard output\n\
262stream before calling @code{input}.\n\
263\n\
264@code{fflush} returns 0 on success and an OS dependent error value\n\
265(@minus{}1 on unix) on error.\n\
266@seealso{fopen, fclose}\n\
267@end deftypefn")
268{
269 octave_value retval = -1;
270
271 int nargin = args.length ();
272
273 if (nargin == 1)
274 {
275 // FIXME -- any way to avoid special case for stdout?
276
277 int fid = octave_stream_list::get_file_number (args (0));
278
279 if (fid == 1)
280 {
281 flush_octave_stdout ();
282
283 retval = 0;
284 }
285 else
286 {
287 octave_stream os = octave_stream_list::lookup (fid, "fflush");
288
289 if (! error_state)
290 retval = os.flush ();
291 }
292 }
293 else
294 print_usage ();
295
296 return retval;
297}
298
299DEFUN (fgetl, args, ,
300 "-*- texinfo -*-\n\
301@deftypefn {Built-in Function} {} fgetl (@var{fid}, @var{len})\n\
302Read characters from a file, stopping after a newline, or EOF,\n\
303or @var{len} characters have been read. The characters read, excluding\n\
304the possible trailing newline, are returned as a string.\n\
305\n\
306If @var{len} is omitted, @code{fgetl} reads until the next newline\n\
307character.\n\
308\n\
309If there are no more characters to read, @code{fgetl} returns @minus{}1.\n\
310@seealso{fread, fscanf}\n\
311@end deftypefn")
312{
313 static std::string who = "fgetl";
314
315 octave_value_list retval;
316
317 retval(1) = 0;
318 retval(0) = -1;
319
320 int nargin = args.length ();
321
322 if (nargin == 1 || nargin == 2)
323 {
324 octave_stream os = octave_stream_list::lookup (args(0), who);
325
326 if (! error_state)
327 {
328 octave_value len_arg = (nargin == 2) ? args(1) : octave_value ();
329
330 bool err = false;
331
332 std::string tmp = os.getl (len_arg, err, who);
333
334 if (! (error_state || err))
335 {
336 retval(1) = tmp.length ();
337 retval(0) = tmp;
338 }
339 }
340 }
341 else
342 print_usage ();
343
344 return retval;
345}
346
347DEFUN (fgets, args, ,
348 "-*- texinfo -*-\n\
349@deftypefn {Built-in Function} {} fgets (@var{fid}, @var{len})\n\
350Read characters from a file, stopping after a newline, or EOF,\n\
351or @var{len} characters have been read. The characters read, including\n\
352the possible trailing newline, are returned as a string.\n\
353\n\
354If @var{len} is omitted, @code{fgets} reads until the next newline\n\
355character.\n\
356\n\
357If there are no more characters to read, @code{fgets} returns @minus{}1.\n\
358@seealso{fputs, fopen, fread, fscanf}\n\
359@end deftypefn")
360{
361 static std::string who = "fgets";
362
363 octave_value_list retval;
364
365 retval(1) = 0.0;
366 retval(0) = -1.0;
367
368 int nargin = args.length ();
369
370 if (nargin == 1 || nargin == 2)
371 {
372 octave_stream os = octave_stream_list::lookup (args(0), who);
373
374 if (! error_state)
375 {
376 octave_value len_arg = (nargin == 2) ? args(1) : octave_value ();
377
378 bool err = false;
379
380 std::string tmp = os.gets (len_arg, err, who);
381
382 if (! (error_state || err))
383 {
384 retval(1) = tmp.length ();
385 retval(0) = tmp;
386 }
387 }
388 }
389 else
390 print_usage ();
391
392 return retval;
393}
394
395DEFUN (fskipl, args, ,
396 "-*- texinfo -*-\n\
397@deftypefn {Built-in Function} {} fskipl (@var{fid}, @var{count})\n\
398Skips a given number of lines, i.e., discards characters until an end-of-line\n\
399is met exactly @var{count}-times, or end-of-file occurs.\n\
400Returns the number of lines skipped (end-of-line sequences encountered).\n\
401If @var{count} is omitted, it defaults to 1. @var{count} may also be\n\
402@code{Inf}, in which case lines are skipped to the end of file.\n\
403This form is suitable for counting lines in a file.\n\
404@seealso{fgetl, fgets}\n\
405@end deftypefn")
406{
407 static std::string who = "fskipl";
408
409 octave_value retval;
410
411 int nargin = args.length ();
412
413 if (nargin == 1 || nargin == 2)
414 {
415 octave_stream os = octave_stream_list::lookup (args(0), who);
416
417 if (! error_state)
418 {
419 octave_value count_arg = (nargin == 2) ? args(1) : octave_value ();
420
421 bool err = false;
422
423 long tmp = os.skipl (count_arg, err, who);
424
425 if (! (error_state || err))
426 retval = tmp;
427 }
428 }
429 else
430 print_usage ();
431
432 return retval;
433}
434
435
436static octave_stream
437do_stream_open (const std::string& name, const std::string& mode,
438 const std::string& arch, int& fid)
439{
440 octave_stream retval;
441
442 fid = -1;
443
444 std::ios::openmode md = fopen_mode_to_ios_mode (mode);
445
446 if (! error_state)
447 {
448 oct_mach_info::float_format flt_fmt =
449 oct_mach_info::string_to_float_format (arch);
450
451 if (! error_state)
452 {
453 std::string fname = file_ops::tilde_expand (name);
454
455 file_stat fs (fname);
456
457 if (! (md & std::ios::out
458 || octave_env::absolute_pathname (fname)
459 || octave_env::rooted_relative_pathname (fname)))
460 {
461 if (! fs.exists ())
462 {
463 std::string tmp
464 = octave_env::make_absolute (load_path::find_file (fname));
465
466 if (! tmp.empty ())
467 {
468 warning_with_id ("Octave:fopen-file-in-path",
469 "fopen: file found in load path");
470 fname = tmp;
471 }
472 }
473 }
474
475 if (! fs.is_dir ())
476 {
477 std::string tmode = mode;
478
479 // Use binary mode if 't' is not specified, but don't add
480 // 'b' if it is already present.
481
482 size_t bpos = tmode.find ('b');
483 size_t tpos = tmode.find ('t');
484
485 if (bpos == std::string::npos && tpos == std::string::npos)
486 tmode += 'b';
487
488#if defined (HAVE_ZLIB)
489 size_t pos = tmode.find ('z');
490
491 if (pos != std::string::npos)
492 {
493 tmode.erase (pos, 1);
494
495 gzFile fptr = ::gzopen (fname.c_str (), tmode.c_str ());
496
497 if (fptr)
498 retval = octave_zstdiostream::create (fname, fptr, md, flt_fmt);
499 else
500 {
501 using namespace std;
502 retval.error (::strerror (errno));
503 }
504 }
505 else
506#endif
507 {
508 FILE *fptr = ::fopen (fname.c_str (), tmode.c_str ());
509
510 retval = octave_stdiostream::create (fname, fptr, md, flt_fmt);
511
512 if (! fptr)
513 {
514 using namespace std;
515 retval.error (::strerror (errno));
516 }
517 }
518
519 }
520 }
521 }
522
523 return retval;
524}
525
526static octave_stream
527do_stream_open (const octave_value& tc_name, const octave_value& tc_mode,
528 const octave_value& tc_arch, const char *fcn, int& fid)
529{
530 octave_stream retval;
531
532 fid = -1;
533
534 std::string name = tc_name.string_value ();
535
536 if (! error_state)
537 {
538 std::string mode = tc_mode.string_value ();
539
540 if (! error_state)
541 {
542 std::string arch = tc_arch.string_value ();
543
544 if (! error_state)
545 retval = do_stream_open (name, mode, arch, fid);
546 else
547 ::error ("%s: architecture type must be a string", fcn);
548 }
549 else
550 ::error ("%s: file mode must be a string", fcn);
551 }
552 else
553 ::error ("%s: file name must be a string", fcn);
554
555 return retval;
556}
557
558DEFUN (fopen, args, ,
559 "-*- texinfo -*-\n\
560@deftypefn {Built-in Function} {[@var{fid}, @var{msg}] =} fopen (@var{name}, @var{mode}, @var{arch})\n\
561@deftypefnx {Built-in Function} {@var{fid_list} =} fopen (\"all\")\n\
562@deftypefnx {Built-in Function} {[@var{file}, @var{mode}, @var{arch}] =} fopen (@var{fid})\n\
563The first form of the @code{fopen} function opens the named file with\n\
564the specified mode (read-write, read-only, etc.) and architecture\n\
565interpretation (IEEE big endian, IEEE little endian, etc.), and returns\n\
566an integer value that may be used to refer to the file later. If an\n\
567error occurs, @var{fid} is set to @minus{}1 and @var{msg} contains the\n\
568corresponding system error message. The @var{mode} is a one or two\n\
569character string that specifies whether the file is to be opened for\n\
570reading, writing, or both.\n\
571\n\
572The second form of the @code{fopen} function returns a vector of file ids\n\
573corresponding to all the currently open files, excluding the\n\
574@code{stdin}, @code{stdout}, and @code{stderr} streams.\n\
575\n\
576The third form of the @code{fopen} function returns information about the\n\
577open file given its file id.\n\
578\n\
579For example,\n\
580\n\
581@example\n\
582myfile = fopen (\"splat.dat\", \"r\", \"ieee-le\");\n\
583@end example\n\
584\n\
585@noindent\n\
586opens the file @file{splat.dat} for reading. If necessary, binary\n\
587numeric values will be read assuming they are stored in IEEE format with\n\
588the least significant bit first, and then converted to the native\n\
589representation.\n\
590\n\
591Opening a file that is already open simply opens it again and returns a\n\
592separate file id. It is not an error to open a file several times,\n\
593though writing to the same file through several different file ids may\n\
594produce unexpected results.\n\
595\n\
596The possible values @samp{mode} may have are\n\
597\n\
598@table @asis\n\
599@item @samp{r}\n\
600Open a file for reading.\n\
601\n\
602@item @samp{w}\n\
603Open a file for writing. The previous contents are discarded.\n\
604\n\
605@item @samp{a}\n\
606Open or create a file for writing at the end of the file.\n\
607\n\
608@item @samp{r+}\n\
609Open an existing file for reading and writing.\n\
610\n\
611@item @samp{w+}\n\
612Open a file for reading or writing. The previous contents are\n\
613discarded.\n\
614\n\
615@item @samp{a+}\n\
616Open or create a file for reading or writing at the end of the\n\
617file.\n\
618@end table\n\
619\n\
620Append a \"t\" to the mode string to open the file in text mode or a\n\
621\"b\" to open in binary mode. On Windows and Macintosh systems, text\n\
622mode reading and writing automatically converts linefeeds to the\n\
623appropriate line end character for the system (carriage-return linefeed\n\
624on Windows, carriage-return on Macintosh). The default if no mode is\n\
625specified is binary mode.\n\
626\n\
627Additionally, you may append a \"z\" to the mode string to open a\n\
628gzipped file for reading or writing. For this to be successful, you\n\
629must also open the file in binary mode.\n\
630\n\
631The parameter @var{arch} is a string specifying the default data format\n\
632for the file. Valid values for @var{arch} are:\n\
633\n\
634@table @asis\n\
635@samp{native}\n\
636The format of the current machine (this is the default).\n\
637\n\
638@samp{ieee-be}\n\
639IEEE big endian format.\n\
640\n\
641@samp{ieee-le}\n\
642IEEE little endian format.\n\
643\n\
644@samp{vaxd}\n\
645VAX D floating format.\n\
646\n\
647@samp{vaxg}\n\
648VAX G floating format.\n\
649\n\
650@samp{cray}\n\
651Cray floating format.\n\
652@end table\n\
653\n\
654@noindent\n\
655however, conversions are currently only supported for @samp{native}\n\
656@samp{ieee-be}, and @samp{ieee-le} formats.\n\
657@seealso{fclose, fgets, fputs, fread, fseek, ferror, fprintf, fscanf, ftell, fwrite}\n\
658@end deftypefn")
659{
660 octave_value_list retval;
661
662 retval(0) = -1.0;
663
664 int nargin = args.length ();
665
666 if (nargin == 1)
667 {
668 if (args(0).is_string ())
669 {
670 // If there is only one argument and it is a string but it
671 // is not the string "all", we assume it is a file to open
672 // with MODE = "r". To open a file called "all", you have
673 // to supply more than one argument.
674
675 if (args(0).string_value () == "all")
676 return octave_stream_list::open_file_numbers ();
677 }
678 else
679 {
680 string_vector tmp = octave_stream_list::get_info (args(0));
681
682 if (! error_state)
683 {
684 retval(2) = tmp(2);
685 retval(1) = tmp(1);
686 retval(0) = tmp(0);
687 }
688
689 return retval;
690 }
691 }
692
693 if (nargin > 0 && nargin < 4)
694 {
695 octave_value mode = (nargin == 2 || nargin == 3)
696 ? args(1) : octave_value ("r");
697
698 octave_value arch = (nargin == 3)
699 ? args(2) : octave_value ("native");
700
701 int fid = -1;
702
703 octave_stream os = do_stream_open (args(0), mode, arch, "fopen", fid);
704
705 if (os && ! error_state)
706 {
707 retval(1) = "";
708 retval(0) = octave_stream_list::insert (os);
709 }
710 else
711 {
712 int error_number = 0;
713
714 retval(1) = os.error (false, error_number);
715 retval(0) = -1.0;
716 }
717 }
718 else
719 print_usage ();
720
721 return retval;
722}
723
724DEFUN (freport, args, ,
725 "-*- texinfo -*-\n\
726@deftypefn {Built-in Function} {} freport ()\n\
727Print a list of which files have been opened, and whether they are open\n\
728for reading, writing, or both. For example,\n\
729\n\
730@example\n\
731@group\n\
732freport ()\n\
733\n\
734 @print{} number mode name\n\
735 @print{} \n\
736 @print{} 0 r stdin\n\
737 @print{} 1 w stdout\n\
738 @print{} 2 w stderr\n\
739 @print{} 3 r myfile\n\
740@end group\n\
741@end example\n\
742@end deftypefn")
743{
744 octave_value_list retval;
745
746 int nargin = args.length ();
747
748 if (nargin > 0)
749 warning ("freport: ignoring extra arguments");
750
751 octave_stdout << octave_stream_list::list_open_files ();
752
753 return retval;
754}
755
756DEFUN (frewind, args, nargout,
757 "-*- texinfo -*-\n\
758@deftypefn {Built-in Function} {} frewind (@var{fid})\n\
759Move the file pointer to the beginning of the file @var{fid}, returning\n\
7600 for success, and -1 if an error was encountered. It is equivalent to\n\
761@code{fseek (@var{fid}, 0, SEEK_SET)}.\n\
762@end deftypefn")
763{
764 octave_value retval;
765
766 int result = -1;
767
768 int nargin = args.length ();
769
770 if (nargin == 1)
771 {
772 octave_stream os = octave_stream_list::lookup (args(0), "frewind");
773
774 if (! error_state)
775 result = os.rewind ();
776 }
777 else
778 print_usage ();
779
780 if (nargout > 0)
781 retval = result;
782
783 return retval;
784}
785
786DEFUN (fseek, args, ,
787 "-*- texinfo -*-\n\
788@deftypefn {Built-in Function} {} fseek (@var{fid}, @var{offset}, @var{origin})\n\
789Set the file pointer to any location within the file @var{fid}.\n\
790\n\
791The pointer is positioned @var{offset} characters from the @var{origin},\n\
792which may be one of the predefined variables @w{@code{SEEK_CUR}} (current\n\
793position), @w{@code{SEEK_SET}} (beginning), or @w{@code{SEEK_END}} (end of\n\
794file) or strings \"cof\", \"bof\" or \"eof\". If @var{origin} is omitted,\n\
795@w{@code{SEEK_SET}} is assumed. The offset must be zero, or a value returned\n\
796by @code{ftell} (in which case @var{origin} must be @w{@code{SEEK_SET}}).\n\
797\n\
798Return 0 on success and -1 on error.\n\
799@seealso{ftell, fopen, fclose}\n\
800@end deftypefn")
801{
802 octave_value retval = -1;
803
804 int nargin = args.length ();
805
806 if (nargin == 2 || nargin == 3)
807 {
808 octave_stream os = octave_stream_list::lookup (args(0), "fseek");
809
810 if (! error_state)
811 {
812 octave_value origin_arg = (nargin == 3)
813 ? args(2) : octave_value (-1.0);
814
815 retval = os.seek (args(1), origin_arg);
816 }
817 }
818 else
819 print_usage ();
820
821 return retval;
822}
823
824DEFUN (ftell, args, ,
825 "-*- texinfo -*-\n\
826@deftypefn {Built-in Function} {} ftell (@var{fid})\n\
827Return the position of the file pointer as the number of characters\n\
828from the beginning of the file @var{fid}.\n\
829@seealso{fseek, fopen, fclose}\n\
830@end deftypefn")
831{
832 octave_value retval = -1;
833
834 int nargin = args.length ();
835
836 if (nargin == 1)
837 {
838 octave_stream os = octave_stream_list::lookup (args(0), "ftell");
839
840 if (! error_state)
841 retval = os.tell ();
842 }
843 else
844 print_usage ();
845
846 return retval;
847}
848
849DEFUN (fprintf, args, nargout,
850 "-*- texinfo -*-\n\
851@deftypefn {Built-in Function} {} fprintf (@var{fid}, @var{template}, @dots{})\n\
852This function is just like @code{printf}, except that the output is\n\
853written to the stream @var{fid} instead of @code{stdout}.\n\
854If @var{fid} is omitted, the output is written to @code{stdout}.\n\
855@seealso{printf, sprintf, fread, fscanf, fopen, fclose}\n\
856@end deftypefn")
857{
858 static std::string who = "fprintf";
859
860 octave_value retval;
861
862 int result = -1;
863
864 int nargin = args.length ();
865
866 if (nargin > 1 || (nargin > 0 && args(0).is_string ()))
867 {
868 octave_stream os;
869 int fmt_n = 0;
870
871 if (args(0).is_string ())
872 {
873 os = octave_stream_list::lookup (1, who);
874 }
875 else
876 {
877 fmt_n = 1;
878 os = octave_stream_list::lookup (args(0), who);
879 }
880
881 if (! error_state)
882 {
883 if (args(fmt_n).is_string ())
884 {
885 octave_value_list tmp_args;
886
887 if (nargin > 1 + fmt_n)
888 {
889 tmp_args.resize (nargin-fmt_n-1, octave_value ());
890
891 for (int i = fmt_n + 1; i < nargin; i++)
892 tmp_args(i-fmt_n-1) = args(i);
893 }
894
895 result = os.printf (args(fmt_n), tmp_args, who);
896 }
897 else
898 ::error ("%s: format must be a string", who.c_str ());
899 }
900 }
901 else
902 print_usage ();
903
904 if (nargout > 0)
905 retval = result;
906
907 return retval;
908}
909
910DEFUN (printf, args, nargout,
911 "-*- texinfo -*-\n\
912@deftypefn {Built-in Function} {} printf (@var{template}, @dots{})\n\
913Print optional arguments under the control of the template string\n\
914@var{template} to the stream @code{stdout} and return the number of\n\
915characters printed.\n\
916@ifclear OCTAVE_MANUAL\n\
917\n\
918See the Formatted Output section of the GNU Octave manual for a\n\
919complete description of the syntax of the template string.\n\
920@end ifclear\n\
921@seealso{fprintf, sprintf, scanf}\n\
922@end deftypefn")
923{
924 static std::string who = "printf";
925
926 octave_value retval;
927
928 int result = -1;
929
930 int nargin = args.length ();
931
932 if (nargin > 0)
933 {
934 if (args(0).is_string ())
935 {
936 octave_value_list tmp_args;
937
938 if (nargin > 1)
939 {
940 tmp_args.resize (nargin-1, octave_value ());
941
942 for (int i = 1; i < nargin; i++)
943 tmp_args(i-1) = args(i);
944 }
945
946 result = stdout_stream.printf (args(0), tmp_args, who);
947 }
948 else
949 ::error ("%s: format must be a string", who.c_str ());
950 }
951 else
952 print_usage ();
953
954 if (nargout > 0)
955 retval = result;
956
957 return retval;
958}
959
960DEFUN (fputs, args, ,
961 "-*- texinfo -*-\n\
962@deftypefn {Built-in Function} {} fputs (@var{fid}, @var{string})\n\
963Write a string to a file with no formatting.\n\
964\n\
965Return a non-negative number on success and EOF on error.\n\
966@seealso{scanf, sscanf, fread, fprintf, fgets, fscanf}\n\
967@end deftypefn")
968{
969 static std::string who = "fputs";
970
971 octave_value retval = -1;
972
973 int nargin = args.length ();
974
975 if (nargin == 2)
976 {
977 octave_stream os = octave_stream_list::lookup (args(0), who);
978
979 if (! error_state)
980 retval = os.puts (args(1), who);
981 }
982 else
983 print_usage ();
984
985 return retval;
986}
987
988DEFUN (puts, args, ,
989 "-*- texinfo -*-\n\
990@deftypefn {Built-in Function} {} puts (@var{string})\n\
991Write a string to the standard output with no formatting.\n\
992\n\
993Return a non-negative number on success and EOF on error.\n\
994@end deftypefn")
995{
996 static std::string who = "puts";
997
998 octave_value retval = -1;
999
1000 if (args.length () == 1)
1001 retval = stdout_stream.puts (args(0), who);
1002 else
1003 print_usage ();
1004
1005 return retval;
1006}
1007
1008DEFUN (sprintf, args, ,
1009 "-*- texinfo -*-\n\
1010@deftypefn {Built-in Function} {} sprintf (@var{template}, @dots{})\n\
1011This is like @code{printf}, except that the output is returned as a\n\
1012string. Unlike the C library function, which requires you to provide a\n\
1013suitably sized string as an argument, Octave's @code{sprintf} function\n\
1014returns the string, automatically sized to hold all of the items\n\
1015converted.\n\
1016@seealso{printf, fprintf, sscanf}\n\
1017@end deftypefn")
1018{
1019 static std::string who = "sprintf";
1020
1021 octave_value_list retval;
1022
1023 int nargin = args.length ();
1024
1025 if (nargin > 0)
1026 {
1027 retval(2) = -1.0;
1028 retval(1) = "unknown error";
1029 retval(0) = "";
1030
1031 octave_ostrstream *ostr = new octave_ostrstream ();
1032
1033 octave_stream os (ostr);
1034
1035 if (os.is_valid ())
1036 {
1037 octave_value fmt_arg = args(0);
1038
1039 if (fmt_arg.is_string ())
1040 {
1041 octave_value_list tmp_args;
1042
1043 if (nargin > 1)
1044 {
1045 tmp_args.resize (nargin-1, octave_value ());
1046
1047 for (int i = 1; i < nargin; i++)
1048 tmp_args(i-1) = args(i);
1049 }
1050
1051 retval(2) = os.printf (fmt_arg, tmp_args, who);
1052 retval(1) = os.error ();
1053 retval(0) = octave_value (ostr->str (),
1054 fmt_arg.is_sq_string () ? '\'' : '"');
1055 }
1056 else
1057 ::error ("%s: format must be a string", who.c_str ());
1058 }
1059 else
1060 ::error ("%s: unable to create output buffer", who.c_str ());
1061 }
1062 else
1063 print_usage ();
1064
1065 return retval;
1066}
1067
1068DEFUN (fscanf, args, ,
1069 "-*- texinfo -*-\n\
1070@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} fscanf (@var{fid}, @var{template}, @var{size})\n\
1071@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} fscanf (@var{fid}, @var{template}, \"C\")\n\
1072In the first form, read from @var{fid} according to @var{template},\n\
1073returning the result in the matrix @var{val}.\n\
1074\n\
1075The optional argument @var{size} specifies the amount of data to read\n\
1076and may be one of\n\
1077\n\
1078@table @code\n\
1079@item Inf\n\
1080Read as much as possible, returning a column vector.\n\
1081\n\
1082@item @var{nr}\n\
1083Read up to @var{nr} elements, returning a column vector.\n\
1084\n\
1085@item [@var{nr}, Inf]\n\
1086Read as much as possible, returning a matrix with @var{nr} rows. If the\n\
1087number of elements read is not an exact multiple of @var{nr}, the last\n\
1088column is padded with zeros.\n\
1089\n\
1090@item [@var{nr}, @var{nc}]\n\
1091Read up to @code{@var{nr} * @var{nc}} elements, returning a matrix with\n\
1092@var{nr} rows. If the number of elements read is not an exact multiple\n\
1093of @var{nr}, the last column is padded with zeros.\n\
1094@end table\n\
1095\n\
1096@noindent\n\
1097If @var{size} is omitted, a value of @code{Inf} is assumed.\n\
1098\n\
1099A string is returned if @var{template} specifies only character\n\
1100conversions.\n\
1101\n\
1102The number of items successfully read is returned in @var{count}.\n\
1103\n\
1104In the second form, read from @var{fid} according to @var{template},\n\
1105with each conversion specifier in @var{template} corresponding to a\n\
1106single scalar return value. This form is more `C-like', and also\n\
1107compatible with previous versions of Octave. The number of successful\n\
1108conversions is returned in @var{count}\n\
1109@ifclear OCTAVE_MANUAL\n\
1110\n\
1111See the Formatted Input section of the GNU Octave manual for a\n\
1112complete description of the syntax of the template string.\n\
1113@end ifclear\n\
1114@seealso{scanf, sscanf, fread, fprintf, fgets, fputs}\n\
1115@end deftypefn")
1116{
1117 static std::string who = "fscanf";
1118
1119 octave_value_list retval;
1120
1121 int nargin = args.length ();
1122
1123 if (nargin == 3 && args(2).is_string ())
1124 {
1125 octave_stream os = octave_stream_list::lookup (args(0), who);
1126
1127 if (! error_state)
1128 {
1129 if (args(1).is_string ())
1130 retval = os.oscanf (args(1), who);
1131 else
1132 ::error ("%s: format must be a string", who.c_str ());
1133 }
1134 }
1135 else
1136 {
1137 retval (1) = 0.0;
1138 retval (0) = Matrix ();
1139
1140 if (nargin == 2 || nargin == 3)
1141 {
1142 octave_stream os = octave_stream_list::lookup (args(0), who);
1143
1144 if (! error_state)
1145 {
1146 if (args(1).is_string ())
1147 {
1148 octave_idx_type count = 0;
1149
1150 Array<double> size = (nargin == 3)
1151 ? args(2).vector_value ()
1152 : Array<double> (1, lo_ieee_inf_value ());
1153
1154 if (! error_state)
1155 {
1156 octave_value tmp = os.scanf (args(1), size, count, who);
1157
1158 if (! error_state)
1159 {
1160 retval(1) = count;
1161 retval(0) = tmp;
1162 }
1163 }
1164 }
1165 else
1166 ::error ("%s: format must be a string", who.c_str ());
1167 }
1168 }
1169 else
1170 print_usage ();
1171 }
1172
1173 return retval;
1174}
1175
1176DEFUN (sscanf, args, ,
1177 "-*- texinfo -*-\n\
1178@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} sscanf (@var{string}, @var{template}, @var{size})\n\
1179@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} sscanf (@var{string}, @var{template}, \"C\")\n\
1180This is like @code{fscanf}, except that the characters are taken from the\n\
1181string @var{string} instead of from a stream. Reaching the end of the\n\
1182string is treated as an end-of-file condition.\n\
1183@seealso{fscanf, scanf, sprintf}\n\
1184@end deftypefn")
1185{
1186 static std::string who = "sscanf";
1187
1188 octave_value_list retval;
1189
1190 int nargin = args.length ();
1191
1192 if (nargin == 3 && args(2).is_string ())
1193 {
1194 if (args(0).is_string ())
1195 {
1196 std::string data = args(0).string_value ();
1197
1198 octave_stream os = octave_istrstream::create (data);
1199
1200 if (os.is_valid ())
1201 {
1202 if (args(1).is_string ())
1203 retval = os.oscanf (args(1), who);
1204 else
1205 ::error ("%s: format must be a string", who.c_str ());
1206 }
1207 else
1208 ::error ("%s: unable to create temporary input buffer",
1209 who.c_str ());
1210 }
1211 else
1212 ::error ("%s: first argument must be a string", who.c_str ());
1213 }
1214 else
1215 {
1216 if (nargin == 2 || nargin == 3)
1217 {
1218 retval(3) = -1.0;
1219 retval(2) = "unknown error";
1220 retval(1) = 0.0;
1221 retval(0) = Matrix ();
1222
1223 if (args(0).is_string ())
1224 {
1225 std::string data = args(0).string_value ();
1226
1227 octave_stream os = octave_istrstream::create (data);
1228
1229 if (os.is_valid ())
1230 {
1231 if (args(1).is_string ())
1232 {
1233 octave_idx_type count = 0;
1234
1235 Array<double> size = (nargin == 3)
1236 ? args(2).vector_value ()
1237 : Array<double> (1, lo_ieee_inf_value ());
1238
1239 octave_value tmp = os.scanf (args(1), size, count, who);
1240
1241 if (! error_state)
1242 {
1243 // FIXME -- is this the right thing to do?
1244 // Extract error message first, because getting
1245 // position will clear it.
1246 std::string errmsg = os.error ();
1247
1248 retval(3) = os.tell () + 1;
1249 retval(2) = errmsg;
1250 retval(1) = count;
1251 retval(0) = tmp;
1252 }
1253 }
1254 else
1255 ::error ("%s: format must be a string", who.c_str ());
1256 }
1257 else
1258 ::error ("%s: unable to create temporary input buffer",
1259 who.c_str ());
1260 }
1261 else
1262 ::error ("%s: first argument must be a string", who.c_str ());
1263 }
1264 else
1265 print_usage ();
1266 }
1267
1268 return retval;
1269}
1270
1271DEFUN (scanf, args, nargout,
1272 "-*- texinfo -*-\n\
1273@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} scanf (@var{template}, @var{size})\n\
1274@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}]] =} scanf (@var{template}, \"C\")\n\
1275This is equivalent to calling @code{fscanf} with @var{fid} = @code{stdin}.\n\
1276\n\
1277It is currently not useful to call @code{scanf} in interactive\n\
1278programs.\n\
1279@seealso{fscanf, sscanf, printf}\n\
1280@end deftypefn")
1281{
1282 int nargin = args.length ();
1283
1284 octave_value_list tmp_args (nargin+1, octave_value ());
1285
1286 tmp_args (0) = 0.0;
1287 for (int i = 0; i < nargin; i++)
1288 tmp_args (i+1) = args (i);
1289
1290 return Ffscanf (tmp_args, nargout);
1291}
1292
1293static octave_value
1294do_fread (octave_stream& os, const octave_value& size_arg,
1295 const octave_value& prec_arg, const octave_value& skip_arg,
1296 const octave_value& arch_arg, octave_idx_type& count)
1297{
1298 octave_value retval;
1299
1300 count = -1;
1301
1302 Array<double> size = size_arg.vector_value ();
1303
1304 if (! error_state)
1305 {
1306 std::string prec = prec_arg.string_value ();
1307
1308 if (! error_state)
1309 {
1310 int block_size = 1;
1311 oct_data_conv::data_type input_type;
1312 oct_data_conv::data_type output_type;
1313
1314 oct_data_conv::string_to_data_type (prec, block_size,
1315 input_type, output_type);
1316
1317 if (! error_state)
1318 {
1319 int skip = skip_arg.int_value (true);
1320
1321 if (! error_state)
1322 {
1323 std::string arch = arch_arg.string_value ();
1324
1325 if (! error_state)
1326 {
1327 oct_mach_info::float_format flt_fmt
1328 = oct_mach_info::string_to_float_format (arch);
1329
1330 if (! error_state)
1331 retval = os.read (size, block_size, input_type,
1332 output_type, skip, flt_fmt, count);
1333 }
1334 else
1335 ::error ("fread: architecture type must be a string");
1336 }
1337 else
1338 ::error ("fread: skip must be an integer");
1339 }
1340 else
1341 ::error ("fread: invalid data type specified");
1342 }
1343 else
1344 ::error ("fread: precision must be a string");
1345 }
1346 else
1347 ::error ("fread: invalid size specified");
1348
1349 return retval;
1350}
1351
1352DEFUN (fread, args, ,
1353 "-*- texinfo -*-\n\
1354@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} fread (@var{fid}, @var{size}, @var{precision}, @var{skip}, @var{arch})\n\
1355Read binary data of type @var{precision} from the specified file ID\n\
1356@var{fid}.\n\
1357\n\
1358The optional argument @var{size} specifies the amount of data to read\n\
1359and may be one of\n\
1360\n\
1361@table @code\n\
1362@item Inf\n\
1363Read as much as possible, returning a column vector.\n\
1364\n\
1365@item @var{nr}\n\
1366Read up to @var{nr} elements, returning a column vector.\n\
1367\n\
1368@item [@var{nr}, Inf]\n\
1369Read as much as possible, returning a matrix with @var{nr} rows. If the\n\
1370number of elements read is not an exact multiple of @var{nr}, the last\n\
1371column is padded with zeros.\n\
1372\n\
1373@item [@var{nr}, @var{nc}]\n\
1374Read up to @code{@var{nr} * @var{nc}} elements, returning a matrix with\n\
1375@var{nr} rows. If the number of elements read is not an exact multiple\n\
1376of @var{nr}, the last column is padded with zeros.\n\
1377@end table\n\
1378\n\
1379@noindent\n\
1380If @var{size} is omitted, a value of @code{Inf} is assumed.\n\
1381\n\
1382The optional argument @var{precision} is a string specifying the type of\n\
1383data to read and may be one of\n\
1384\n\
1385@table @code\n\
1386@item \"schar\"\n\
1387@itemx \"signed char\"\n\
1388Signed character.\n\
1389\n\
1390@item \"uchar\"\n\
1391@itemx \"unsigned char\"\n\
1392Unsigned character.\n\
1393\n\
1394@item \"int8\"\n\
1395@itemx \"integer*1\"\n\
1396\n\
13978-bit signed integer.\n\
1398\n\
1399@item \"int16\"\n\
1400@itemx \"integer*2\"\n\
140116-bit signed integer.\n\
1402\n\
1403@item \"int32\"\n\
1404@itemx \"integer*4\"\n\
140532-bit signed integer.\n\
1406\n\
1407@item \"int64\"\n\
1408@itemx \"integer*8\"\n\
140964-bit signed integer.\n\
1410\n\
1411@item \"uint8\"\n\
14128-bit unsigned integer.\n\
1413\n\
1414@item \"uint16\"\n\
141516-bit unsigned integer.\n\
1416\n\
1417@item \"uint32\"\n\
141832-bit unsigned integer.\n\
1419\n\
1420@item \"uint64\"\n\
142164-bit unsigned integer.\n\
1422\n\
1423@item \"single\"\n\
1424@itemx \"float32\"\n\
1425@itemx \"real*4\"\n\
142632-bit floating point number.\n\
1427\n\
1428@item \"double\"\n\
1429@itemx \"float64\"\n\
1430@itemx \"real*8\"\n\
143164-bit floating point number.\n\
1432\n\
1433@item \"char\"\n\
1434@itemx \"char*1\"\n\
1435Single character.\n\
1436\n\
1437@item \"short\"\n\
1438Short integer (size is platform dependent).\n\
1439\n\
1440@item \"int\"\n\
1441Integer (size is platform dependent).\n\
1442\n\
1443@item \"long\"\n\
1444Long integer (size is platform dependent).\n\
1445\n\
1446@item \"ushort\"\n\
1447@itemx \"unsigned short\"\n\
1448Unsigned short integer (size is platform dependent).\n\
1449\n\
1450@item \"uint\"\n\
1451@itemx \"unsigned int\"\n\
1452Unsigned integer (size is platform dependent).\n\
1453\n\
1454@item \"ulong\"\n\
1455@itemx \"unsigned long\"\n\
1456Unsigned long integer (size is platform dependent).\n\
1457\n\
1458@item \"float\"\n\
1459Single precision floating point number (size is platform dependent).\n\
1460@end table\n\
1461\n\
1462@noindent\n\
1463The default precision is @code{\"uchar\"}.\n\
1464\n\
1465The @var{precision} argument may also specify an optional repeat\n\
1466count. For example, @samp{32*single} causes @code{fread} to read\n\
1467a block of 32 single precision floating point numbers. Reading in\n\
1468blocks is useful in combination with the @var{skip} argument.\n\
1469\n\
1470The @var{precision} argument may also specify a type conversion.\n\
1471For example, @samp{int16=>int32} causes @code{fread} to read 16-bit\n\
1472integer values and return an array of 32-bit integer values. By\n\
1473default, @code{fread} returns a double precision array. The special\n\
1474form @samp{*TYPE} is shorthand for @samp{TYPE=>TYPE}.\n\
1475\n\
1476The conversion and repeat counts may be combined. For example, the\n\
1477specification @samp{32*single=>single} causes @code{fread} to read\n\
1478blocks of single precision floating point values and return an array\n\
1479of single precision values instead of the default array of double\n\
1480precision values.\n\
1481\n\
1482The optional argument @var{skip} specifies the number of bytes to skip\n\
1483after each element (or block of elements) is read. If it is not\n\
1484specified, a value of 0 is assumed. If the final block read is not\n\
1485complete, the final skip is omitted. For example,\n\
1486\n\
1487@example\n\
1488fread (f, 10, \"3*single=>single\", 8)\n\
1489@end example\n\
1490\n\
1491@noindent\n\
1492will omit the final 8-byte skip because the last read will not be\n\
1493a complete block of 3 values.\n\
1494\n\
1495The optional argument @var{arch} is a string specifying the data format\n\
1496for the file. Valid values are\n\
1497\n\
1498@table @code\n\
1499@item \"native\"\n\
1500The format of the current machine.\n\
1501\n\
1502@item \"ieee-be\"\n\
1503IEEE big endian.\n\
1504\n\
1505@item \"ieee-le\"\n\
1506IEEE little endian.\n\
1507\n\
1508@item \"vaxd\"\n\
1509VAX D floating format.\n\
1510\n\
1511@item \"vaxg\"\n\
1512VAX G floating format.\n\
1513\n\
1514@item \"cray\"\n\
1515Cray floating format.\n\
1516@end table\n\
1517\n\
1518@noindent\n\
1519Conversions are currently only supported for @code{\"ieee-be\"} and\n\
1520@code{\"ieee-le\"} formats.\n\
1521\n\
1522The data read from the file is returned in @var{val}, and the number of\n\
1523values read is returned in @code{count}\n\
1524@seealso{fwrite, fopen, fclose}\n\
1525@end deftypefn")
1526{
1527 octave_value_list retval;
1528
1529 int nargin = args.length ();
1530
1531 if (nargin > 0 && nargin < 6)
1532 {
1533 retval(1) = -1.0;
1534 retval(0) = Matrix ();
1535
1536 octave_stream os = octave_stream_list::lookup (args(0), "fread");
1537
1538 if (! error_state)
1539 {
1540 octave_value size = lo_ieee_inf_value ();
1541 octave_value prec = "uchar";
1542 octave_value skip = 0;
1543 octave_value arch = "unknown";
1544
1545 int idx = 1;
1546
1547 if (nargin > idx && ! args(idx).is_string ())
1548 size = args(idx++);
1549
1550 if (nargin > idx)
1551 prec = args(idx++);
1552
1553 if (nargin > idx)
1554 skip = args(idx++);
1555
1556 if (nargin > idx)
1557 arch = args(idx++);
1558 else if (skip.is_string ())
1559 {
1560 arch = skip;
1561 skip = 0;
1562 }
1563
1564 octave_idx_type count = -1;
1565
1566 octave_value tmp = do_fread (os, size, prec, skip, arch, count);
1567
1568 retval(1) = count;
1569 retval(0) = tmp;
1570 }
1571 }
1572 else
1573 print_usage ();
1574
1575 return retval;
1576}
1577
1578static int
1579do_fwrite (octave_stream& os, const octave_value& data,
1580 const octave_value& prec_arg, const octave_value& skip_arg,
1581 const octave_value& arch_arg)
1582{
1583 int retval = -1;
1584
1585 std::string prec = prec_arg.string_value ();
1586
1587 if (! error_state)
1588 {
1589 int block_size = 1;
1590 oct_data_conv::data_type output_type;
1591
1592 oct_data_conv::string_to_data_type (prec, block_size, output_type);
1593
1594 if (! error_state)
1595 {
1596 int skip = skip_arg.int_value (true);
1597
1598 if (! error_state)
1599 {
1600 std::string arch = arch_arg.string_value ();
1601
1602 if (! error_state)
1603 {
1604 oct_mach_info::float_format flt_fmt
1605 = oct_mach_info::string_to_float_format (arch);
1606
1607 if (! error_state)
1608 retval = os.write (data, block_size, output_type,
1609 skip, flt_fmt);
1610 }
1611 else
1612 ::error ("fwrite: architecture type must be a string");
1613 }
1614 else
1615 ::error ("fwrite: skip must be an integer");
1616 }
1617 else
1618 ::error ("fwrite: invalid precision specified");
1619 }
1620 else
1621 ::error ("fwrite: precision must be a string");
1622
1623 return retval;
1624}
1625
1626DEFUN (fwrite, args, ,
1627 "-*- texinfo -*-\n\
1628@deftypefn {Built-in Function} {@var{count} =} fwrite (@var{fid}, @var{data}, @var{precision}, @var{skip}, @var{arch})\n\
1629Write data in binary form of type @var{precision} to the specified file\n\
1630ID @var{fid}, returning the number of values successfully written to the\n\
1631file.\n\
1632\n\
1633The argument @var{data} is a matrix of values that are to be written to\n\
1634the file. The values are extracted in column-major order.\n\
1635\n\
1636The remaining arguments @var{precision}, @var{skip}, and @var{arch} are\n\
1637optional, and are interpreted as described for @code{fread}.\n\
1638\n\
1639The behavior of @code{fwrite} is undefined if the values in @var{data}\n\
1640are too large to fit in the specified precision.\n\
1641@seealso{fread, fopen, fclose}\n\
1642@end deftypefn")
1643{
1644 octave_value retval = -1;
1645
1646 int nargin = args.length ();
1647
1648 if (nargin > 1 && nargin < 6)
1649 {
1650 octave_stream os = octave_stream_list::lookup (args(0), "fwrite");
1651
1652 if (! error_state)
1653 {
1654 octave_value prec = "uchar";
1655 octave_value skip = 0;
1656 octave_value arch = "unknown";
1657
1658 int idx = 1;
1659
1660 octave_value data = args(idx++);
1661
1662 if (nargin > idx)
1663 prec = args(idx++);
1664
1665 if (nargin > idx)
1666 skip = args(idx++);
1667
1668 if (nargin > idx)
1669 arch = args(idx++);
1670 else if (skip.is_string ())
1671 {
1672 arch = skip;
1673 skip = 0;
1674 }
1675
1676 double status = do_fwrite (os, data, prec, skip, arch);
1677
1678 retval = status;
1679 }
1680 }
1681 else
1682 print_usage ();
1683
1684 return retval;
1685}
1686
1687DEFUNX ("feof", Ffeof, args, ,
1688 "-*- texinfo -*-\n\
1689@deftypefn {Built-in Function} {} feof (@var{fid})\n\
1690Return 1 if an end-of-file condition has been encountered for a given\n\
1691file and 0 otherwise. Note that it will only return 1 if the end of the\n\
1692file has already been encountered, not if the next read operation will\n\
1693result in an end-of-file condition.\n\
1694@seealso{fread, fopen, fclose}\n\
1695@end deftypefn")
1696{
1697 octave_value retval = -1;
1698
1699 int nargin = args.length ();
1700
1701 if (nargin == 1)
1702 {
1703 octave_stream os = octave_stream_list::lookup (args(0), "feof");
1704
1705 if (! error_state)
1706 retval = os.eof () ? 1.0 : 0.0;
1707 }
1708 else
1709 print_usage ();
1710
1711 return retval;
1712}
1713
1714DEFUNX ("ferror", Fferror, args, ,
1715 "-*- texinfo -*-\n\
1716@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} ferror (@var{fid}, \"clear\")\n\
1717Return 1 if an error condition has been encountered for the file ID\n\
1718@var{fid} and 0 otherwise. Note that it will only return 1 if an error\n\
1719has already been encountered, not if the next operation will result in\n\
1720an error condition.\n\
1721\n\
1722The second argument is optional. If it is supplied, also clear the\n\
1723error condition.\n\
1724@end deftypefn")
1725{
1726 octave_value_list retval;
1727
1728 int nargin = args.length ();
1729
1730 if (nargin == 1 || nargin == 2)
1731 {
1732 octave_stream os = octave_stream_list::lookup (args(0), "ferror");
1733
1734 if (! error_state)
1735 {
1736 bool clear = false;
1737
1738 if (nargin == 2)
1739 {
1740 std::string opt = args(1).string_value ();
1741
1742 if (! error_state)
1743 clear = (opt == "clear");
1744 else
1745 return retval;
1746 }
1747
1748 int error_number = 0;
1749
1750 std::string error_message = os.error (clear, error_number);
1751
1752 retval(1) = error_number;
1753 retval(0) = error_message;
1754 }
1755 }
1756 else
1757 print_usage ();
1758
1759 return retval;
1760}
1761
1762DEFUN (popen, args, ,
1763 "-*- texinfo -*-\n\
1764@deftypefn {Built-in Function} {@var{fid} =} popen (@var{command}, @var{mode})\n\
1765Start a process and create a pipe. The name of the command to run is\n\
1766given by @var{command}. The file identifier corresponding to the input\n\
1767or output stream of the process is returned in @var{fid}. The argument\n\
1768@var{mode} may be\n\
1769\n\
1770@table @code\n\
1771@item \"r\"\n\
1772The pipe will be connected to the standard output of the process, and\n\
1773open for reading.\n\
1774\n\
1775@item \"w\"\n\
1776The pipe will be connected to the standard input of the process, and\n\
1777open for writing.\n\
1778@end table\n\
1779\n\
1780For example,\n\
1781\n\
1782@example\n\
1783@group\n\
1784fid = popen (\"ls -ltr / | tail -3\", \"r\");\n\
1785while (ischar (s = fgets (fid)))\n\
1786 fputs (stdout, s);\n\
1787endwhile\n\
1788 @print{} drwxr-xr-x 33 root root 3072 Feb 15 13:28 etc\n\
1789 @print{} drwxr-xr-x 3 root root 1024 Feb 15 13:28 lib\n\
1790 @print{} drwxrwxrwt 15 root root 2048 Feb 17 14:53 tmp\n\
1791@end group\n\
1792@end example\n\
1793@end deftypefn")
1794{
1795 octave_value retval = -1;
1796
1797 int nargin = args.length ();
1798
1799 if (nargin == 2)
1800 {
1801 std::string name = args(0).string_value ();
1802
1803 if (! error_state)
1804 {
1805 std::string mode = args(1).string_value ();
1806
1807 if (! error_state)
1808 {
1809 if (mode == "r")
1810 {
1811 octave_stream ips = octave_iprocstream::create (name);
1812
1813 retval = octave_stream_list::insert (ips);
1814 }
1815 else if (mode == "w")
1816 {
1817 octave_stream ops = octave_oprocstream::create (name);
1818
1819 retval = octave_stream_list::insert (ops);
1820 }
1821 else
1822 ::error ("popen: invalid mode specified");
1823 }
1824 else
1825 ::error ("popen: mode must be a string");
1826 }
1827 else
1828 ::error ("popen: name must be a string");
1829 }
1830 else
1831 print_usage ();
1832
1833 return retval;
1834}
1835
1836DEFUN (pclose, args, ,
1837 "-*- texinfo -*-\n\
1838@deftypefn {Built-in Function} {} pclose (@var{fid})\n\
1839Close a file identifier that was opened by @code{popen}. You may also\n\
1840use @code{fclose} for the same purpose.\n\
1841@end deftypefn")
1842{
1843 octave_value retval = -1;
1844
1845 int nargin = args.length ();
1846
1847 if (nargin == 1)
1848 retval = octave_stream_list::remove (args(0), "pclose");
1849 else
1850 print_usage ();
1851
1852 return retval;
1853}
1854
1855DEFUNX ("tmpnam", Ftmpnam, args, ,
1856 "-*- texinfo -*-\n\
1857@deftypefn {Built-in Function} {} tmpnam (@var{dir}, @var{prefix})\n\
1858Return a unique temporary file name as a string.\n\
1859\n\
1860If @var{prefix} is omitted, a value of @code{\"oct-\"} is used.\n\
1861If @var{dir} is also omitted, the default directory for temporary files\n\
1862is used. If @var{dir} is provided, it must exist, otherwise the default\n\
1863directory for temporary files is used. Since the named file is not\n\
1864opened, by @code{tmpnam}, it is possible (though relatively unlikely)\n\
1865that it will not be available by the time your program attempts to open it.\n\
1866@seealso{tmpfile, mkstemp, P_tmpdir}\n\
1867@end deftypefn")
1868{
1869 octave_value retval;
1870
1871 int len = args.length ();
1872
1873 if (len < 3)
1874 {
1875 std::string dir = len > 0 ? args(0).string_value () : std::string ();
1876
1877 if (! error_state)
1878 {
1879 std::string pfx
1880 = len > 1 ? args(1).string_value () : std::string ("oct-");
1881
1882 if (! error_state)
1883 retval = octave_tempnam (dir, pfx);
1884 else
1885 ::error ("expecting second argument to be a string");
1886 }
1887 else
1888 ::error ("expecting first argument to be a string");
1889 }
1890 else
1891 print_usage ();
1892
1893 return retval;
1894}
1895
1896DEFALIAS (octave_tmp_file_name, tmpnam);
1897
1898DEFUN (tmpfile, args, ,
1899 "-*- texinfo -*-\n\
1900@deftypefn {Built-in Function} {[@var{fid}, @var{msg}] =} tmpfile ()\n\
1901Return the file ID corresponding to a new temporary file with a unique\n\
1902name. The file is opened in binary read/write (@code{\"w+b\"}) mode.\n\
1903The file will be deleted automatically when it is closed or when Octave\n\
1904exits.\n\
1905\n\
1906If successful, @var{fid} is a valid file ID and @var{msg} is an empty\n\
1907string. Otherwise, @var{fid} is -1 and @var{msg} contains a\n\
1908system-dependent error message.\n\
1909@seealso{tmpnam, mkstemp, P_tmpdir}\n\
1910@end deftypefn")
1911{
1912 octave_value_list retval;
1913
1914 retval(1) = std::string ();
1915 retval(0) = -1;
1916
1917 int nargin = args.length ();
1918
1919 if (nargin == 0)
1920 {
1921 FILE *fid = tmpfile ();
1922
1923 if (fid)
1924 {
1925 std::string nm;
1926
1927 std::ios::openmode md = fopen_mode_to_ios_mode ("w+b");
1928
1929 octave_stream s = octave_stdiostream::create (nm, fid, md);
1930
1931 if (s)
1932 retval(0) = octave_stream_list::insert (s);
1933 else
1934 error ("tmpfile: failed to create octave_stdiostream object");
1935
1936 }
1937 else
1938 {
1939 using namespace std;
1940 retval(1) = ::strerror (errno);
1941 retval(0) = -1;
1942 }
1943 }
1944 else
1945 print_usage ();
1946
1947 return retval;
1948}
1949
1950#if defined (HAVE_MKSTEMPS)
1951// Prototype for mkstemps in libiberty
1952extern "C" int mkstemps (char *pattern, int suffix_len);
1953#endif
1954
1955#if ! defined (HAVE_MKSTEMP) && ! defined (HAVE_MKSTEMPS) && defined (_MSC_VER)
1956#include <fcntl.h>
1957#include <sys/stat.h>
1958int mkstemp (char *tmpl)
1959{
1960 int ret=-1;
1961 mktemp (tmpl);
1962 ret = open (tmpl, O_RDWR | O_BINARY | O_CREAT | O_EXCL | _O_SHORT_LIVED,
1963 _S_IREAD | _S_IWRITE);
1964 return ret;
1965}
1966#define HAVE_MKSTEMP 1
1967#endif
1968
1969DEFUN (mkstemp, args, ,
1970 "-*- texinfo -*-\n\
1971@deftypefn {Built-in Function} {[@var{fid}, @var{name}, @var{msg}] =} mkstemp (@var{template}, @var{delete})\n\
1972Return the file ID corresponding to a new temporary file with a unique\n\
1973name created from @var{template}. The last six characters of @var{template}\n\
1974must be @code{XXXXXX} and these are replaced with a string that makes the\n\
1975filename unique. The file is then created with mode read/write and\n\
1976permissions that are system dependent (on GNU/Linux systems, the permissions\n\
1977will be 0600 for versions of glibc 2.0.7 and later). The file is opened\n\
1978with the @w{@code{O_EXCL}} flag.\n\
1979\n\
1980If the optional argument @var{delete} is supplied and is true,\n\
1981the file will be deleted automatically when Octave exits, or when\n\
1982the function @code{purge_tmp_files} is called.\n\
1983\n\
1984If successful, @var{fid} is a valid file ID, @var{name} is the name of\n\
1985the file, and @var{msg} is an empty string. Otherwise, @var{fid}\n\
1986is -1, @var{name} is empty, and @var{msg} contains a system-dependent\n\
1987error message.\n\
1988@seealso{tmpfile, tmpnam, P_tmpdir}\n\
1989@end deftypefn")
1990{
1991 octave_value_list retval;
1992
1993 retval(2) = std::string ();
1994 retval(1) = std::string ();
1995 retval(0) = -1;
1996
1997#if defined (HAVE_MKSTEMP) || defined (HAVE_MKSTEMPS)
1998
1999 int nargin = args.length ();
2000
2001 if (nargin == 1 || nargin == 2)
2002 {
2003 std::string tmpl8 = args(0).string_value ();
2004
2005 if (! error_state)
2006 {
2007 OCTAVE_LOCAL_BUFFER (char, tmp, tmpl8.size () + 1);
2008 strcpy (tmp, tmpl8.c_str ());
2009
2010#if defined (HAVE_MKSTEMP)
2011 int fd = mkstemp (tmp);
2012#else
2013 int fd = mkstemps (tmp, 0);
2014#endif
2015
2016 if (fd < 0)
2017 {
2018 using namespace std;
2019 retval(2) = ::strerror (errno);
2020 retval(0) = fd;
2021 }
2022 else
2023 {
2024 const char *fopen_mode = "w+";
2025
2026 FILE *fid = fdopen (fd, fopen_mode);
2027
2028 if (fid)
2029 {
2030 std::string nm = tmp;
2031
2032 std::ios::openmode md = fopen_mode_to_ios_mode (fopen_mode);
2033
2034 octave_stream s = octave_stdiostream::create (nm, fid, md);
2035
2036 if (s)
2037 {
2038 retval(1) = nm;
2039 retval(0) = octave_stream_list::insert (s);
2040
2041 if (nargin == 2 && args(1).is_true ())
2042 mark_for_deletion (nm);
2043 }
2044 else
2045 error ("mkstemp: failed to create octave_stdiostream object");
2046 }
2047 else
2048 {
2049 using namespace std;
2050 retval(2) = ::strerror (errno);
2051 retval(0) = -1;
2052 }
2053 }
2054 }
2055 else
2056 error ("mkstemp: expecting string as first argument");
2057 }
2058 else
2059 print_usage ();
2060
2061#else
2062 retval(2) = "mkstemp: not supported on this sytem";
2063#endif
2064
2065 return retval;
2066}
2067
2068static int
2069convert (int x, int ibase, int obase)
2070{
2071 int retval = 0;
2072
2073 int tmp = x % obase;
2074
2075 if (tmp > ibase - 1)
2076 ::error ("umask: invalid digit");
2077 else
2078 {
2079 retval = tmp;
2080 int mult = ibase;
2081 while ((x = (x - tmp) / obase))
2082 {
2083 tmp = x % obase;
2084 if (tmp > ibase - 1)
2085 {
2086 ::error ("umask: invalid digit");
2087 break;
2088 }
2089 retval += mult * tmp;
2090 mult *= ibase;
2091 }
2092 }
2093
2094 return retval;
2095}
2096
2097DEFUNX ("umask", Fumask, args, ,
2098 "-*- texinfo -*-\n\
2099@deftypefn {Built-in Function} {} umask (@var{mask})\n\
2100Set the permission mask for file creation. The parameter @var{mask}\n\
2101is an integer, interpreted as an octal number. If successful,\n\
2102returns the previous value of the mask (as an integer to be\n\
2103interpreted as an octal number); otherwise an error message is printed.\n\
2104@end deftypefn")
2105{
2106 octave_value_list retval;
2107
2108 int status = 0;
2109
2110 if (args.length () == 1)
2111 {
2112 int mask = args(0).int_value (true);
2113
2114 if (! error_state)
2115 {
2116 if (mask < 0)
2117 {
2118 status = -1;
2119 ::error ("umask: MASK must be a positive integer value");
2120 }
2121 else
2122 {
2123 int oct_mask = convert (mask, 8, 10);
2124
2125 if (! error_state)
2126 status = convert (octave_umask (oct_mask), 10, 8);
2127 }
2128 }
2129 else
2130 {
2131 status = -1;
2132 ::error ("umask: expecting integer argument");
2133 }
2134 }
2135 else
2136 print_usage ();
2137
2138 if (status >= 0)
2139 retval(0) = status;
2140
2141 return retval;
2142}
2143
2144static octave_value
2145const_value (const char *, const octave_value_list& args, int val)
2146{
2147 octave_value retval;
2148
2149 int nargin = args.length ();
2150
2151 if (nargin == 0)
2152 retval = val;
2153 else
2154 print_usage ();
2155
2156 return retval;
2157}
2158
2159#if ! defined (P_tmpdir)
2160#define P_tmpdir "/tmp"
2161#endif
2162
2163DEFUNX ("P_tmpdir", FP_tmpdir, args, ,
2164 "-*- texinfo -*-\n\
2165@deftypefn {Built-in Function} {} P_tmpdir ()\n\
2166Return the default name of the directory for temporary files on\n\
2167this system. The name of this directory is system dependent.\n\
2168@end deftypefn")
2169{
2170 octave_value retval;
2171
2172 int nargin = args.length ();
2173
2174 if (nargin == 0)
2175 retval = P_tmpdir;
2176 else
2177 print_usage ();
2178
2179 return retval;
2180}
2181
2182// NOTE: the values of SEEK_SET, SEEK_CUR, and SEEK_END have to be
2183// this way for Matlab compatibility.
2184
2185DEFUNX ("SEEK_SET", FSEEK_SET, args, ,
2186 "-*- texinfo -*-\n\
2187@deftypefn {Built-in Function} {} SEEK_SET ()\n\
2188@deftypefnx {Built-in Function} {} SEEK_CUR ()\n\
2189@deftypefnx {Built-in Function} {} SEEK_END ()\n\
2190Return the value required to request that @code{fseek} perform\n\
2191one of the following actions:\n\
2192@table @code\n\
2193@item SEEK_SET\n\
2194Position file relative to the beginning.\n\
2195\n\
2196@item SEEK_CUR\n\
2197Position file relative to the current position.\n\
2198\n\
2199@item SEEK_END\n\
2200Position file relative to the end.\n\
2201@end table\n\
2202@end deftypefn")
2203{
2204 return const_value ("SEEK_SET", args, -1);
2205}
2206
2207DEFUNX ("SEEK_CUR", FSEEK_CUR, args, ,
2208 "-*- texinfo -*-\n\
2209@deftypefn {Built-in Function} {} SEEK_CUR ()\n\
2210See SEEK_SET.\n\
2211@end deftypefn")
2212{
2213 return const_value ("SEEK_CUR", args, 0);
2214}
2215
2216DEFUNX ("SEEK_END", FSEEK_END, args, ,
2217 "-*- texinfo -*-\n\
2218@deftypefn {Built-in Function} {} SEEK_END ()\n\
2219See SEEK_SET.\n\
2220@end deftypefn")
2221{
2222 return const_value ("SEEK_END", args, 1);
2223}
2224
2225static octave_value
2226const_value (const char *, const octave_value_list& args,
2227 const octave_value& val)
2228{
2229 octave_value retval;
2230
2231 int nargin = args.length ();
2232
2233 if (nargin == 0)
2234 retval = val;
2235 else
2236 print_usage ();
2237
2238 return retval;
2239}
2240
2241DEFUNX ("stdin", Fstdin, args, ,
2242 "-*- texinfo -*-\n\
2243@deftypefn {Built-in Function} {} stdin ()\n\
2244Return the numeric value corresponding to the standard input stream.\n\
2245When Octave is used interactively, this is filtered through the command\n\
2246line editing functions.\n\
2247@seealso{stdout, stderr}\n\
2248@end deftypefn")
2249{
2250 return const_value ("stdin", args, stdin_file);
2251}
2252
2253DEFUNX ("stdout", Fstdout, args, ,
2254 "-*- texinfo -*-\n\
2255@deftypefn {Built-in Function} {} stdout ()\n\
2256Return the numeric value corresponding to the standard output stream.\n\
2257Data written to the standard output is normally filtered through the pager.\n\
2258@seealso{stdin, stderr}\n\
2259@end deftypefn")
2260{
2261 return const_value ("stdout", args, stdout_file);
2262}
2263
2264DEFUNX ("stderr", Fstderr, args, ,
2265 "-*- texinfo -*-\n\
2266@deftypefn {Built-in Function} {} stderr ()\n\
2267Return the numeric value corresponding to the standard error stream.\n\
2268Even if paging is turned on, the standard error is not sent to the\n\
2269pager. It is useful for error messages and prompts.\n\
2270@seealso{stdin, stdout}\n\
2271@end deftypefn")
2272{
2273 return const_value ("stderr", args, stderr_file);
2274}