1
|
1 // file-io.cc -*- C++ -*- |
|
2 /* |
|
3 |
1009
|
4 Copyright (C) 1993, 1994, 1995 John W. Eaton |
1
|
5 |
|
6 This file is part of Octave. |
|
7 |
|
8 Octave is free software; you can redistribute it and/or modify it |
|
9 under the terms of the GNU General Public License as published by the |
|
10 Free Software Foundation; either version 2, or (at your option) any |
|
11 later version. |
|
12 |
|
13 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
16 for more details. |
|
17 |
|
18 You should have received a copy of the GNU General Public License |
|
19 along with Octave; see the file COPYING. If not, write to the Free |
|
20 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
21 |
|
22 */ |
|
23 |
|
24 // Written by John C. Campbell <jcc@che.utexas.edu>. |
|
25 |
240
|
26 #ifdef HAVE_CONFIG_H |
|
27 #include "config.h" |
1
|
28 #endif |
|
29 |
|
30 #include <DLList.h> |
|
31 #include <unistd.h> |
|
32 #include <string.h> |
|
33 #include <stdio.h> |
444
|
34 #include <errno.h> |
1
|
35 #include <stdlib.h> |
|
36 #include <strstream.h> |
|
37 #include <ctype.h> |
|
38 |
456
|
39 #include "dMatrix.h" |
444
|
40 |
1
|
41 #include "statdefs.h" |
|
42 #include "file-io.h" |
|
43 #include "input.h" |
|
44 #include "octave-hist.h" |
|
45 #include "tree-const.h" |
|
46 #include "error.h" |
542
|
47 #include "help.h" |
1
|
48 #include "utils.h" |
|
49 #include "pager.h" |
529
|
50 #include "defun.h" |
444
|
51 #include "sysdep.h" |
|
52 #include "mappers.h" |
529
|
53 #include "variables.h" |
1
|
54 |
|
55 // keeps a count of args sent to printf or scanf |
|
56 static int fmt_arg_count = 0; |
|
57 |
759
|
58 // double linked list containing relevant information about open files |
|
59 static DLList <file_info> file_list; |
1
|
60 |
240
|
61 file_info::file_info (void) |
1
|
62 { |
334
|
63 file_number = -1; |
529
|
64 file_name = 0; |
|
65 file_fptr = 0; |
|
66 file_mode = 0; |
1
|
67 } |
|
68 |
240
|
69 file_info::file_info (int n, const char *nm, FILE *t, const char *md) |
|
70 { |
334
|
71 file_number = n; |
|
72 file_name = strsave (nm); |
|
73 file_fptr = t; |
|
74 file_mode = strsave (md); |
240
|
75 } |
|
76 |
|
77 file_info::file_info (const file_info& f) |
1
|
78 { |
367
|
79 file_number = f.file_number; |
|
80 file_name = strsave (f.file_name); |
|
81 file_fptr = f.file_fptr; |
|
82 file_mode = strsave (f.file_mode); |
1
|
83 } |
|
84 |
240
|
85 file_info& |
|
86 file_info::operator = (const file_info& f) |
1
|
87 { |
240
|
88 if (this != & f) |
|
89 { |
367
|
90 file_number = f.file_number; |
334
|
91 delete [] file_name; |
|
92 file_name = strsave (f.file_name); |
|
93 file_fptr = f.file_fptr; |
|
94 delete [] file_mode; |
|
95 file_mode = strsave (f.file_mode); |
240
|
96 } |
1
|
97 return *this; |
|
98 } |
|
99 |
240
|
100 file_info::~file_info (void) |
1
|
101 { |
334
|
102 delete [] file_name; |
|
103 delete [] file_mode; |
1
|
104 } |
|
105 |
|
106 int |
240
|
107 file_info::number (void) const |
1
|
108 { |
334
|
109 return file_number; |
1
|
110 } |
|
111 |
240
|
112 const char * |
|
113 file_info::name (void) const |
1
|
114 { |
334
|
115 return file_name; |
1
|
116 } |
|
117 |
|
118 FILE * |
240
|
119 file_info::fptr (void) const |
1
|
120 { |
334
|
121 return file_fptr; |
1
|
122 } |
|
123 |
240
|
124 const char * |
|
125 file_info::mode (void) const |
1
|
126 { |
334
|
127 return file_mode; |
1
|
128 } |
|
129 |
|
130 void |
164
|
131 initialize_file_io (void) |
1
|
132 { |
334
|
133 file_info octave_stdin (0, "stdin", stdin, "r"); |
|
134 file_info octave_stdout (1, "stdout", stdout, "w"); |
|
135 file_info octave_stderr (2, "stderr", stderr, "w"); |
1
|
136 |
334
|
137 file_list.append (octave_stdin); |
|
138 file_list.append (octave_stdout); |
|
139 file_list.append (octave_stderr); |
1
|
140 } |
|
141 |
761
|
142 // Given a file name or number, return a pointer to the corresponding |
|
143 // open file. If the file has not already been opened, return NULL. |
|
144 |
1
|
145 Pix |
164
|
146 return_valid_file (const tree_constant& arg) |
1
|
147 { |
610
|
148 if (arg.is_string ()) |
1
|
149 { |
|
150 Pix p = file_list.first (); |
240
|
151 file_info file; |
896
|
152 int file_count = file_list.length (); |
1
|
153 for (int i = 0; i < file_count; i++) |
|
154 { |
|
155 char *file_name = arg.string_value (); |
|
156 file = file_list (p); |
|
157 if (strcmp (file.name (), file_name) == 0) |
|
158 return p; |
|
159 file_list.next (p); |
|
160 } |
|
161 } |
636
|
162 else |
1
|
163 { |
|
164 double file_num = arg.double_value (); |
636
|
165 |
|
166 if (! error_state) |
1
|
167 { |
1086
|
168 if (D_NINT (file_num) != file_num) |
636
|
169 error ("file number not an integer value"); |
|
170 else |
1
|
171 { |
636
|
172 Pix p = file_list.first (); |
|
173 file_info file; |
896
|
174 int file_count = file_list.length (); |
636
|
175 for (int i = 0; i < file_count; i++) |
|
176 { |
|
177 file = file_list (p); |
|
178 if (file.number () == file_num) |
|
179 return p; |
|
180 file_list.next (p); |
|
181 } |
|
182 error ("no file with that number"); |
1
|
183 } |
|
184 } |
636
|
185 else |
|
186 error ("inapproriate file specifier"); |
|
187 } |
1
|
188 |
529
|
189 return 0; |
1
|
190 } |
|
191 |
|
192 static Pix |
636
|
193 fopen_file_for_user (const char *name, const char *mode, |
370
|
194 const char *warn_for) |
1
|
195 { |
636
|
196 FILE *file_ptr = fopen (name, mode); |
529
|
197 if (file_ptr) |
1
|
198 { |
896
|
199 int file_number = file_list.length () + 1; |
|
200 |
|
201 file_info file (file_number, name, file_ptr, mode); |
1
|
202 file_list.append (file); |
|
203 |
|
204 Pix p = file_list.first (); |
240
|
205 file_info file_from_list; |
896
|
206 int file_count = file_list.length (); |
1
|
207 for (int i = 0; i < file_count; i++) |
|
208 { |
|
209 file_from_list = file_list (p); |
636
|
210 if (strcmp (file_from_list.name (), name) == 0) |
1
|
211 return p; |
|
212 file_list.next (p); |
|
213 } |
|
214 } |
|
215 |
636
|
216 error ("%s: unable to open file `%s'", warn_for, name); |
240
|
217 |
529
|
218 return 0; |
1
|
219 } |
|
220 |
368
|
221 static Pix |
636
|
222 file_io_get_file (const tree_constant& arg, const char *mode, |
368
|
223 const char *warn_for) |
|
224 { |
|
225 Pix p = return_valid_file (arg); |
|
226 |
529
|
227 if (! p) |
368
|
228 { |
610
|
229 if (arg.is_string ()) |
368
|
230 { |
|
231 char *name = arg.string_value (); |
|
232 |
|
233 struct stat buffer; |
|
234 int status = stat (name, &buffer); |
|
235 |
372
|
236 if (status == 0) |
368
|
237 { |
|
238 if ((buffer.st_mode & S_IFREG) == S_IFREG) |
636
|
239 p = fopen_file_for_user (name, mode, warn_for); |
368
|
240 else |
|
241 error ("%s: invalid file type", warn_for); |
|
242 } |
372
|
243 else if (status < 0 && *mode != 'r') |
636
|
244 p = fopen_file_for_user (name, mode, warn_for); |
368
|
245 else |
|
246 error ("%s: can't stat file `%s'", warn_for, name); |
|
247 } |
|
248 else |
|
249 error ("%s: invalid file specifier", warn_for); |
|
250 } |
|
251 |
|
252 return p; |
|
253 } |
1
|
254 |
1181
|
255 static Octave_object |
497
|
256 fclose_internal (const Octave_object& args) |
1
|
257 { |
497
|
258 Octave_object retval; |
1
|
259 |
712
|
260 Pix p = return_valid_file (args(0)); |
1
|
261 |
529
|
262 if (! p) |
1
|
263 return retval; |
|
264 |
240
|
265 file_info file = file_list (p); |
1
|
266 |
|
267 if (file.number () < 3) |
|
268 { |
|
269 warning ("fclose: can't close stdin, stdout, or stderr!"); |
|
270 return retval; |
|
271 } |
|
272 |
|
273 int success = fclose (file.fptr ()); |
|
274 file_list.del (p); |
|
275 |
|
276 if (success == 0) |
636
|
277 retval(0) = 1.0; // succeeded |
1
|
278 else |
|
279 { |
|
280 error ("fclose: error on closing file"); |
636
|
281 retval(0) = 0.0; // failed |
1
|
282 } |
|
283 |
|
284 return retval; |
|
285 } |
|
286 |
1181
|
287 DEFUN ("fclose", Ffclose, Sfclose, 1, 1, |
|
288 "fclose (FILENAME or FILENUM): close a file") |
529
|
289 { |
|
290 Octave_object retval; |
|
291 |
|
292 int nargin = args.length (); |
|
293 |
712
|
294 if (nargin != 1) |
1181
|
295 print_usage ("fclose"); |
529
|
296 else |
1181
|
297 retval = fclose_internal (args); |
529
|
298 |
|
299 return retval; |
|
300 } |
|
301 |
1181
|
302 static Octave_object |
497
|
303 fflush_internal (const Octave_object& args) |
1
|
304 { |
497
|
305 Octave_object retval; |
1
|
306 |
712
|
307 Pix p = return_valid_file (args(0)); |
1
|
308 |
529
|
309 if (! p) |
1
|
310 return retval; |
|
311 |
240
|
312 file_info file = file_list (p); |
1
|
313 |
|
314 if (strcmp (file.mode (), "r") == 0) |
|
315 { |
|
316 warning ("can't flush an input stream"); |
|
317 return retval; |
|
318 } |
|
319 |
|
320 int success = 0; |
240
|
321 |
1
|
322 if (file.number () == 1) |
|
323 flush_output_to_pager (); |
|
324 else |
|
325 success = fflush (file.fptr ()); |
|
326 |
|
327 if (success == 0) |
636
|
328 retval(0) = 1.0; // succeeded |
1
|
329 else |
|
330 { |
|
331 error ("fflush: write error"); |
636
|
332 retval(0) = 0.0; // failed |
1
|
333 } |
|
334 |
|
335 return retval; |
|
336 } |
|
337 |
1181
|
338 DEFUN ("fflush", Ffflush, Sfflush, 1, 1, |
|
339 "fflush (FILENAME or FILENUM): flush buffered data to output file") |
|
340 { |
|
341 Octave_object retval; |
|
342 |
|
343 int nargin = args.length (); |
|
344 |
|
345 if (nargin != 1) |
|
346 print_usage ("fflush"); |
|
347 else |
|
348 retval = fflush_internal (args); |
|
349 |
|
350 return retval; |
|
351 } |
|
352 |
1
|
353 static int |
164
|
354 valid_mode (const char *mode) |
1
|
355 { |
529
|
356 if (mode) |
1
|
357 { |
|
358 char m = mode[0]; |
|
359 if (m == 'r' || m == 'w' || m == 'a') |
|
360 { |
|
361 m = mode[1]; |
|
362 return (m == '\0' || (m == '+' && mode[2] == '\0')); |
|
363 } |
|
364 } |
|
365 return 0; |
|
366 } |
|
367 |
1181
|
368 static Octave_object |
497
|
369 fgets_internal (const Octave_object& args, int nargout) |
1
|
370 { |
497
|
371 Octave_object retval; |
1
|
372 |
712
|
373 Pix p = file_io_get_file (args(0), "r", "fgets"); |
1
|
374 |
529
|
375 if (! p) |
368
|
376 return retval; |
|
377 |
636
|
378 |
712
|
379 double dlen = args(1).double_value (); |
636
|
380 |
|
381 if (error_state) |
|
382 return retval; |
|
383 |
1086
|
384 if (xisnan (dlen)) |
|
385 { |
|
386 error ("fgets: NaN invalid as length"); |
|
387 return retval; |
|
388 } |
|
389 |
636
|
390 int length = NINT (dlen); |
|
391 |
|
392 if ((double) length != dlen) |
1
|
393 { |
636
|
394 error ("fgets: length not an integer value"); |
|
395 return retval; |
1
|
396 } |
|
397 |
368
|
398 file_info file = file_list (p); |
|
399 |
636
|
400 char string [length+1]; |
1
|
401 char *success = fgets (string, length+1, file.fptr ()); |
|
402 |
529
|
403 if (! success) |
1
|
404 { |
636
|
405 retval(0) = -1.0; |
1
|
406 return retval; |
|
407 } |
|
408 |
|
409 if (nargout == 2) |
636
|
410 retval(1) = (double) strlen (string); |
1
|
411 |
636
|
412 retval(0) = string; |
1
|
413 |
|
414 return retval; |
|
415 } |
|
416 |
1181
|
417 DEFUN ("fgets", Ffgets, Sfgets, 2, 2, |
|
418 "[STRING, LENGTH] = fgets (FILENAME or FILENUM, LENGTH)\n\ |
529
|
419 \n\ |
1181
|
420 read a string from a file") |
529
|
421 { |
|
422 Octave_object retval; |
|
423 |
|
424 int nargin = args.length (); |
|
425 |
712
|
426 if (nargin != 2) |
1181
|
427 print_usage ("fgets"); |
529
|
428 else |
1181
|
429 retval = fgets_internal (args, nargout); |
529
|
430 |
|
431 return retval; |
|
432 } |
|
433 |
1181
|
434 static Octave_object |
497
|
435 fopen_internal (const Octave_object& args) |
1
|
436 { |
497
|
437 Octave_object retval; |
1
|
438 Pix p; |
|
439 |
712
|
440 if (! args(0).is_string ()) |
1
|
441 { |
|
442 error ("fopen: file name must be a string"); |
|
443 return retval; |
|
444 } |
|
445 |
712
|
446 p = return_valid_file (args(0)); |
1
|
447 |
529
|
448 if (p) |
1
|
449 { |
240
|
450 file_info file = file_list (p); |
1
|
451 |
636
|
452 retval(0) = (double) file.number (); |
1
|
453 |
|
454 return retval; |
|
455 } |
|
456 |
712
|
457 if (! args(1).is_string ()) |
1
|
458 { |
370
|
459 error ("fopen: file mode must be a string"); |
1
|
460 return retval; |
|
461 } |
|
462 |
712
|
463 char *name = args(0).string_value (); |
|
464 char *mode = args(1).string_value (); |
1
|
465 |
|
466 if (! valid_mode (mode)) |
|
467 { |
|
468 error ("fopen: invalid mode"); |
|
469 return retval; |
|
470 } |
|
471 |
|
472 struct stat buffer; |
|
473 if (stat (name, &buffer) == 0 && (buffer.st_mode & S_IFDIR) == S_IFDIR) |
|
474 { |
|
475 error ("fopen: can't open directory"); |
|
476 return retval; |
|
477 } |
|
478 |
|
479 FILE *file_ptr = fopen (name, mode); |
|
480 |
529
|
481 if (! file_ptr) |
1
|
482 { |
370
|
483 error ("fopen: unable to open file `%s'", name); |
1
|
484 return retval; |
|
485 } |
|
486 |
896
|
487 int file_number = file_list.length () + 1; |
1
|
488 |
896
|
489 file_info file (file_number, name, file_ptr, mode); |
1
|
490 file_list.append (file); |
|
491 |
896
|
492 retval(0) = (double) file_number; |
1
|
493 |
|
494 return retval; |
|
495 } |
|
496 |
1181
|
497 DEFUN ("fopen", Ffopen, Sfopen, 2, 1, |
|
498 "FILENUM = fopen (FILENAME, MODE): open a file\n\ |
|
499 \n\ |
|
500 Valid values for mode include:\n\ |
|
501 \n\ |
|
502 r : open text file for reading\n\ |
|
503 w : open text file for writing; discard previous contents if any\n\ |
|
504 a : append; open or create text file for writing at end of file\n\ |
|
505 r+ : open text file for update (i.e., reading and writing)\n\ |
|
506 w+ : create text file for update; discard previous contents if any\n\ |
|
507 a+ : append; open or create text file for update, writing at end\n\n\ |
|
508 Update mode permits reading from and writing to the same file.") |
529
|
509 { |
|
510 Octave_object retval; |
|
511 |
|
512 int nargin = args.length (); |
|
513 |
1181
|
514 if (nargin != 2) |
|
515 print_usage ("fopen"); |
|
516 else |
|
517 retval = fopen_internal (args); |
529
|
518 |
|
519 return retval; |
|
520 } |
|
521 |
1181
|
522 static Octave_object |
164
|
523 freport_internal (void) |
1
|
524 { |
497
|
525 Octave_object retval; |
1
|
526 Pix p = file_list.first (); |
|
527 |
|
528 ostrstream output_buf; |
|
529 |
|
530 output_buf << "\n number mode name\n\n"; |
896
|
531 |
|
532 int file_count = file_list.length (); |
1
|
533 for (int i = 0; i < file_count; i++) |
|
534 { |
240
|
535 file_info file = file_list (p); |
1
|
536 output_buf.form ("%7d%6s %s\n", file.number (), file.mode (), |
|
537 file.name ()); |
|
538 file_list.next (p); |
|
539 } |
|
540 |
|
541 output_buf << "\n" << ends; |
|
542 maybe_page_output (output_buf); |
|
543 |
|
544 return retval; |
|
545 } |
|
546 |
1181
|
547 DEFUN ("freport", Ffreport, Sfreport, 0, 1, |
|
548 "freport (): list open files and their status") |
|
549 { |
|
550 Octave_object retval; |
|
551 |
|
552 int nargin = args.length (); |
|
553 |
|
554 if (nargin > 0) |
|
555 warning ("freport: ignoring extra arguments"); |
|
556 |
|
557 retval = freport_internal (); |
|
558 |
|
559 return retval; |
|
560 } |
|
561 |
|
562 static Octave_object |
|
563 frewind_internal (const Octave_object& args) |
|
564 { |
|
565 Octave_object retval; |
|
566 |
|
567 Pix p = file_io_get_file (args(0), "a+", "frewind"); |
|
568 |
|
569 if (p) |
|
570 { |
|
571 file_info file = file_list (p); |
|
572 rewind (file.fptr ()); |
|
573 } |
|
574 |
|
575 return retval; |
|
576 } |
|
577 |
712
|
578 DEFUN ("frewind", Ffrewind, Sfrewind, 1, 1, |
529
|
579 "frewind (FILENAME or FILENUM): set file position at beginning of file") |
|
580 { |
|
581 Octave_object retval; |
|
582 |
|
583 int nargin = args.length (); |
|
584 |
712
|
585 if (nargin != 1) |
529
|
586 print_usage ("frewind"); |
|
587 else |
|
588 retval = frewind_internal (args); |
|
589 |
|
590 return retval; |
|
591 } |
|
592 |
1181
|
593 static Octave_object |
506
|
594 fseek_internal (const Octave_object& args) |
1
|
595 { |
497
|
596 Octave_object retval; |
1
|
597 |
506
|
598 int nargin = args.length (); |
|
599 |
712
|
600 Pix p = file_io_get_file (args(0), "a+", "fseek"); |
1
|
601 |
529
|
602 if (! p) |
368
|
603 return retval; |
1
|
604 |
|
605 long origin = SEEK_SET; |
636
|
606 |
712
|
607 double doff = args(1).double_value (); |
636
|
608 |
|
609 if (error_state) |
|
610 return retval; |
|
611 |
1086
|
612 if (xisnan (doff)) |
|
613 { |
|
614 error ("fseek: NaN invalid as offset"); |
|
615 return retval; |
|
616 } |
|
617 |
636
|
618 long offset = NINT (doff); |
|
619 |
|
620 if ((double) offset != doff) |
1
|
621 { |
636
|
622 error ("fseek: offset not an integer value"); |
|
623 return retval; |
|
624 } |
|
625 |
712
|
626 if (nargin == 3) |
636
|
627 { |
712
|
628 double dorig = args(2).double_value (); |
636
|
629 |
|
630 if (error_state) |
|
631 return retval; |
|
632 |
1086
|
633 if (xisnan (dorig)) |
|
634 { |
|
635 error ("fseek: NaN invalid as origin"); |
|
636 return retval; |
|
637 } |
|
638 |
636
|
639 origin = NINT (dorig); |
|
640 |
|
641 if ((double) dorig != origin) |
1
|
642 { |
636
|
643 error ("fseek: origin not an integer value"); |
1
|
644 return retval; |
|
645 } |
|
646 |
763
|
647 if (origin == 0) |
|
648 origin = SEEK_SET; |
|
649 else if (origin == 1) |
1
|
650 origin = SEEK_CUR; |
763
|
651 else if (origin == 2) |
1
|
652 origin = SEEK_END; |
|
653 else |
|
654 { |
636
|
655 error ("fseek: invalid value for origin"); |
|
656 return retval; |
1
|
657 } |
|
658 } |
|
659 |
240
|
660 file_info file = file_list (p); |
1
|
661 int success = fseek (file.fptr (), offset, origin); |
|
662 |
|
663 if (success == 0) |
636
|
664 retval(0) = 1.0; // succeeded |
1
|
665 else |
|
666 { |
|
667 error ("fseek: file error"); |
636
|
668 retval(0) = 0.0; // failed |
1
|
669 } |
|
670 |
|
671 return retval; |
|
672 } |
|
673 |
1181
|
674 DEFUN ("fseek", Ffseek, Sfseek, 3, 1, |
|
675 "fseek (FILENAME or FILENUM, OFFSET [, ORIGIN])\n\ |
|
676 \n\ |
|
677 set file position for reading or writing") |
529
|
678 { |
|
679 Octave_object retval; |
|
680 |
|
681 int nargin = args.length (); |
|
682 |
1181
|
683 if (nargin != 2 && nargin != 3) |
|
684 print_usage ("fseek"); |
529
|
685 else |
1181
|
686 retval = fseek_internal (args); |
529
|
687 |
|
688 return retval; |
|
689 } |
|
690 |
1181
|
691 // Tell current position of file. |
|
692 |
|
693 static Octave_object |
497
|
694 ftell_internal (const Octave_object& args) |
1
|
695 { |
497
|
696 Octave_object retval; |
1
|
697 |
712
|
698 Pix p = file_io_get_file (args(0), "a+", "ftell"); |
1
|
699 |
529
|
700 if (p) |
368
|
701 { |
|
702 file_info file = file_list (p); |
|
703 long offset = ftell (file.fptr ()); |
636
|
704 |
|
705 retval(0) = (double) offset; |
1
|
706 |
368
|
707 if (offset == -1L) |
|
708 error ("ftell: write error"); |
|
709 } |
1
|
710 |
|
711 return retval; |
|
712 } |
|
713 |
1181
|
714 DEFUN ("ftell", Fftell, Sftell, 1, 1, |
|
715 "POSITION = ftell (FILENAME or FILENUM): returns the current file position") |
|
716 { |
|
717 Octave_object retval; |
|
718 |
|
719 int nargin = args.length (); |
|
720 |
|
721 if (nargin != 1) |
|
722 print_usage ("ftell"); |
|
723 else |
|
724 retval = ftell_internal (args); |
|
725 |
|
726 return retval; |
|
727 } |
|
728 |
1
|
729 void |
164
|
730 close_files (void) |
1
|
731 { |
|
732 Pix p = file_list.first (); |
|
733 |
896
|
734 int file_count = file_list.length (); |
1
|
735 for (int i = 0; i < file_count; i++) |
|
736 { |
896
|
737 if (p) |
1
|
738 { |
896
|
739 file_info file = file_list (p); |
|
740 |
|
741 if (i > 2) // do not close stdin, stdout, stderr! |
|
742 { |
|
743 int success = fclose (file.fptr ()); |
|
744 if (success != 0) |
|
745 error ("closing %s", file.name ()); |
|
746 } |
|
747 |
|
748 file_list.del (p); |
1
|
749 } |
896
|
750 else |
|
751 { |
|
752 error ("inconsistent state for internal file list!"); |
|
753 break; |
|
754 } |
1
|
755 } |
|
756 } |
|
757 |
|
758 static int |
497
|
759 process_printf_format (const char *s, const Octave_object& args, |
506
|
760 ostrstream& sb, const char *type) |
1
|
761 { |
|
762 ostrstream fmt; |
|
763 |
506
|
764 int nargin = args.length (); |
|
765 |
1
|
766 fmt << "%"; // do_printf() already blew past this one... |
|
767 |
|
768 int chars_from_fmt_str = 0; |
|
769 |
|
770 again: |
|
771 switch (*s) |
|
772 { |
|
773 case '+': case '-': case ' ': case '0': case '#': |
|
774 chars_from_fmt_str++; |
|
775 fmt << *s++; |
|
776 goto again; |
|
777 |
|
778 case '\0': |
|
779 goto invalid_format; |
|
780 |
|
781 default: |
|
782 break; |
|
783 } |
|
784 |
|
785 if (*s == '*') |
|
786 { |
712
|
787 if (fmt_arg_count > nargin) |
1
|
788 { |
218
|
789 error ("%s: not enough arguments", type); |
1
|
790 return -1; |
|
791 } |
|
792 |
636
|
793 double tmp_len = args(fmt_arg_count++).double_value (); |
|
794 |
1086
|
795 if (error_state || xisnan (tmp_len)) |
1
|
796 { |
218
|
797 error ("%s: `*' must be replaced by an integer", type); |
1
|
798 return -1; |
|
799 } |
|
800 |
636
|
801 fmt << NINT (tmp_len); |
1
|
802 s++; |
|
803 chars_from_fmt_str++; |
|
804 } |
|
805 else |
|
806 { |
|
807 while (*s != '\0' && isdigit (*s)) |
|
808 { |
|
809 chars_from_fmt_str++; |
|
810 fmt << *s++; |
|
811 } |
|
812 } |
|
813 |
|
814 if (*s == '\0') |
|
815 goto invalid_format; |
|
816 |
|
817 if (*s == '.') |
|
818 { |
|
819 chars_from_fmt_str++; |
|
820 fmt << *s++; |
|
821 } |
|
822 |
|
823 if (*s == '*') |
|
824 { |
|
825 if (*(s-1) == '*') |
|
826 goto invalid_format; |
|
827 |
712
|
828 if (fmt_arg_count > nargin) |
1
|
829 { |
218
|
830 error ("%s: not enough arguments", type); |
1
|
831 return -1; |
|
832 } |
|
833 |
636
|
834 double tmp_len = args(fmt_arg_count++).double_value (); |
|
835 |
1086
|
836 if (error_state || xisnan (tmp_len)) |
1
|
837 { |
218
|
838 error ("%s: `*' must be replaced by an integer", type); |
1
|
839 return -1; |
|
840 } |
|
841 |
636
|
842 fmt << NINT (tmp_len); |
1
|
843 s++; |
|
844 chars_from_fmt_str++; |
|
845 } |
|
846 else |
|
847 { |
|
848 while (*s != '\0' && isdigit (*s)) |
|
849 { |
|
850 chars_from_fmt_str++; |
|
851 fmt << *s++; |
|
852 } |
|
853 } |
|
854 |
|
855 if (*s == '\0') |
|
856 goto invalid_format; |
|
857 |
|
858 if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L')) |
|
859 { |
|
860 chars_from_fmt_str++; |
|
861 fmt << *s++; |
|
862 } |
|
863 |
|
864 if (*s == '\0') |
|
865 goto invalid_format; |
|
866 |
712
|
867 if (fmt_arg_count > nargin) |
1
|
868 { |
218
|
869 error ("%s: not enough arguments", type); |
1
|
870 return -1; |
|
871 } |
|
872 |
|
873 switch (*s) |
|
874 { |
|
875 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': |
636
|
876 { |
|
877 double d = args(fmt_arg_count++).double_value (); |
1
|
878 |
1086
|
879 if (error_state || xisnan (d)) |
|
880 goto invalid_conversion; |
|
881 |
636
|
882 int val = NINT (d); |
|
883 |
1086
|
884 if ((double) val != d) |
636
|
885 goto invalid_conversion; |
|
886 else |
|
887 { |
|
888 chars_from_fmt_str++; |
|
889 fmt << *s << ends; |
|
890 char *tmp_fmt = fmt.str (); |
|
891 sb.form (tmp_fmt, val); |
|
892 delete [] tmp_fmt; |
|
893 return chars_from_fmt_str; |
|
894 } |
|
895 } |
1
|
896 |
|
897 case 'e': case 'E': case 'f': case 'g': case 'G': |
636
|
898 { |
|
899 double val = args(fmt_arg_count++).double_value (); |
1
|
900 |
636
|
901 if (error_state) |
|
902 goto invalid_conversion; |
|
903 else |
|
904 { |
|
905 chars_from_fmt_str++; |
|
906 fmt << *s << ends; |
|
907 char *tmp_fmt = fmt.str (); |
|
908 sb.form (tmp_fmt, val); |
|
909 delete [] tmp_fmt; |
|
910 return chars_from_fmt_str; |
|
911 } |
|
912 } |
1
|
913 |
|
914 case 's': |
636
|
915 { |
|
916 char *val = args(fmt_arg_count++).string_value (); |
1
|
917 |
636
|
918 if (error_state) |
|
919 goto invalid_conversion; |
|
920 else |
|
921 { |
|
922 chars_from_fmt_str++; |
|
923 fmt << *s << ends; |
|
924 char *tmp_fmt = fmt.str (); |
|
925 sb.form (tmp_fmt, val); |
|
926 delete [] tmp_fmt; |
|
927 return chars_from_fmt_str; |
|
928 } |
|
929 } |
1
|
930 |
|
931 case 'c': |
636
|
932 { |
|
933 char *val = args(fmt_arg_count++).string_value (); |
1
|
934 |
636
|
935 if (error_state || strlen (val) != 1) |
|
936 goto invalid_conversion; |
|
937 else |
|
938 { |
|
939 chars_from_fmt_str++; |
|
940 fmt << *s << ends; |
|
941 char *tmp_fmt = fmt.str (); |
|
942 sb.form (tmp_fmt, *val); |
|
943 delete [] tmp_fmt; |
|
944 return chars_from_fmt_str; |
|
945 } |
|
946 } |
1
|
947 |
|
948 default: |
|
949 goto invalid_format; |
|
950 } |
|
951 |
|
952 invalid_conversion: |
218
|
953 error ("%s: invalid conversion", type); |
1
|
954 return -1; |
|
955 |
|
956 invalid_format: |
218
|
957 error ("%s: invalid format", type); |
1
|
958 return -1; |
|
959 } |
|
960 |
761
|
961 // Formatted printing to a file. |
1
|
962 |
1181
|
963 static Octave_object |
506
|
964 do_printf (const char *type, const Octave_object& args, int nargout) |
1
|
965 { |
497
|
966 Octave_object retval; |
712
|
967 fmt_arg_count = 0; |
1
|
968 char *fmt; |
240
|
969 file_info file; |
1
|
970 |
|
971 if (strcmp (type, "fprintf") == 0) |
|
972 { |
712
|
973 Pix p = file_io_get_file (args(0), "a+", type); |
368
|
974 |
529
|
975 if (! p) |
368
|
976 return retval; |
1
|
977 |
|
978 file = file_list (p); |
368
|
979 |
1
|
980 if (file.mode () == "r") |
|
981 { |
|
982 error ("%s: file is read only", type); |
|
983 return retval; |
|
984 } |
368
|
985 |
712
|
986 fmt = args(1).string_value (); |
368
|
987 |
636
|
988 if (error_state) |
|
989 { |
|
990 error ("%s: format must be a string", type); |
|
991 return retval; |
|
992 } |
|
993 |
|
994 fmt_arg_count += 2; |
1
|
995 } |
|
996 else |
|
997 { |
712
|
998 fmt = args(0).string_value (); |
636
|
999 |
|
1000 if (error_state) |
|
1001 { |
|
1002 error ("%s: invalid format string", type); |
|
1003 return retval; |
|
1004 } |
|
1005 |
|
1006 fmt_arg_count++; |
1
|
1007 } |
|
1008 |
|
1009 // Scan fmt for % escapes and print out the arguments. |
|
1010 |
|
1011 ostrstream output_buf; |
|
1012 |
|
1013 char *ptr = fmt; |
|
1014 |
|
1015 for (;;) |
|
1016 { |
|
1017 char c; |
|
1018 while ((c = *ptr++) != '\0' && c != '%') |
|
1019 output_buf << c; |
|
1020 |
|
1021 if (c == '\0') |
|
1022 break; |
|
1023 |
|
1024 if (*ptr == '%') |
|
1025 { |
|
1026 ptr++; |
|
1027 output_buf << c; |
|
1028 continue; |
|
1029 } |
|
1030 |
|
1031 // We must be looking at a format specifier. Extract it or fail. |
|
1032 |
506
|
1033 int status = process_printf_format (ptr, args, output_buf, type); |
1
|
1034 |
|
1035 if (status < 0) |
|
1036 return retval; |
|
1037 |
|
1038 ptr += status; |
|
1039 } |
|
1040 |
|
1041 output_buf << ends; |
|
1042 if (strcmp (type, "printf") == 0 |
|
1043 || (strcmp (type, "fprintf") == 0 && file.number () == 1)) |
|
1044 { |
|
1045 maybe_page_output (output_buf); |
|
1046 } |
|
1047 else if (strcmp (type, "fprintf") == 0) |
|
1048 { |
|
1049 char *msg = output_buf.str (); |
|
1050 int success = fputs (msg, file.fptr ()); |
|
1051 if (success == EOF) |
218
|
1052 warning ("%s: unknown failure writing to file", type); |
1
|
1053 delete [] msg; |
|
1054 } |
|
1055 else if (strcmp (type, "sprintf") == 0) |
|
1056 { |
|
1057 char *msg = output_buf.str (); |
636
|
1058 retval(0) = msg; |
1
|
1059 delete [] msg; |
|
1060 } |
|
1061 |
|
1062 return retval; |
|
1063 } |
|
1064 |
1181
|
1065 DEFUN ("fprintf", Ffprintf, Sfprintf, -1, 1, |
|
1066 "fprintf (FILENAME or FILENUM, FORMAT, ...)") |
|
1067 { |
|
1068 Octave_object retval; |
|
1069 |
|
1070 int nargin = args.length (); |
|
1071 |
|
1072 if (nargin < 2) |
|
1073 print_usage ("fprintf"); |
|
1074 else |
|
1075 retval = do_printf ("fprintf", args, nargout); |
|
1076 |
|
1077 return retval; |
|
1078 } |
|
1079 |
|
1080 // Formatted printing. |
|
1081 |
|
1082 DEFUN ("printf", Fprintf, Sprintf, -1, 1, |
|
1083 "printf (FORMAT, ...)") |
|
1084 { |
|
1085 Octave_object retval; |
|
1086 |
|
1087 int nargin = args.length (); |
|
1088 |
|
1089 if (nargin < 1) |
|
1090 print_usage ("printf"); |
|
1091 else |
|
1092 retval = do_printf ("printf", args, nargout); |
|
1093 |
|
1094 return retval; |
|
1095 } |
|
1096 |
|
1097 // Formatted printing to a string. |
|
1098 |
|
1099 DEFUN ("sprintf", Fsprintf, Ssprintf, -1, 1, |
|
1100 "s = sprintf (FORMAT, ...)") |
|
1101 { |
|
1102 Octave_object retval; |
|
1103 |
|
1104 int nargin = args.length (); |
|
1105 |
|
1106 if (nargin < 1) |
|
1107 print_usage ("sprintf"); |
|
1108 else |
|
1109 retval = do_printf ("sprintf", args, nargout); |
|
1110 |
|
1111 return retval; |
|
1112 } |
|
1113 |
1
|
1114 static int |
368
|
1115 process_scanf_format (const char *s, ostrstream& fmt, |
|
1116 const char *type, int nargout, FILE* fptr, |
497
|
1117 Octave_object& values) |
1
|
1118 { |
|
1119 fmt << "%"; |
|
1120 |
|
1121 int chars_from_fmt_str = 0; |
|
1122 int store_value = 1; |
628
|
1123 int string_width = 0; |
1
|
1124 int success = 1; |
|
1125 |
|
1126 if (*s == '*') |
|
1127 { |
|
1128 store_value = 0; |
|
1129 s++; |
|
1130 chars_from_fmt_str++; |
|
1131 } |
|
1132 |
|
1133 if (isdigit (*s)) |
|
1134 { |
|
1135 ostrstream str_number; |
|
1136 while (*s != '\0' && isdigit (*s)) |
|
1137 { |
|
1138 chars_from_fmt_str++; |
|
1139 str_number << *s; |
|
1140 fmt << *s++; |
|
1141 } |
|
1142 str_number << ends; |
|
1143 char *number = str_number.str (); |
|
1144 string_width = atoi (number); |
|
1145 delete [] number; |
|
1146 } |
|
1147 |
|
1148 if (*s == '\0') |
|
1149 goto invalid_format; |
|
1150 |
|
1151 if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L')) |
|
1152 { |
|
1153 chars_from_fmt_str++; |
|
1154 s++; |
|
1155 } |
|
1156 |
|
1157 if (*s == '\0') |
|
1158 goto invalid_format; |
|
1159 |
368
|
1160 // Even if we don't have a place to store them, attempt to convert |
|
1161 // everything specified by the format string. |
1
|
1162 |
712
|
1163 if (fmt_arg_count > (nargout ? nargout : 1)) |
368
|
1164 store_value = 0; |
1
|
1165 |
|
1166 switch (*s) |
|
1167 { |
|
1168 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': |
|
1169 { |
|
1170 chars_from_fmt_str++; |
|
1171 fmt << *s << ends; |
|
1172 int temp; |
|
1173 char *str = fmt.str (); |
|
1174 success = fscanf (fptr, str, &temp); |
|
1175 delete [] str; |
|
1176 if (success > 0 && store_value) |
636
|
1177 values(fmt_arg_count++) = (double) temp; |
1
|
1178 } |
|
1179 break; |
628
|
1180 |
1
|
1181 case 'e': case 'E': case 'f': case 'g': case 'G': |
|
1182 { |
|
1183 chars_from_fmt_str++; |
|
1184 fmt << 'l' << *s << ends; |
|
1185 double temp; |
|
1186 char *str = fmt.str (); |
|
1187 success = fscanf (fptr, str, &temp); |
|
1188 delete [] str; |
|
1189 if (success > 0 && store_value) |
636
|
1190 values(fmt_arg_count++) = temp; |
1
|
1191 } |
|
1192 break; |
628
|
1193 |
1
|
1194 case 's': |
|
1195 { |
|
1196 if (string_width < 1) |
|
1197 { |
628
|
1198 // XXX FIXME XXX -- The code below is miscompiled on the Alpha with |
|
1199 // gcc 2.6.0, so that string_width is never incremented, even though |
|
1200 // reading the data works correctly. One fix is to use a fixed-size |
|
1201 // buffer... |
|
1202 // string_width = 8192; |
|
1203 |
1
|
1204 string_width = 0; |
|
1205 long original_position = ftell (fptr); |
628
|
1206 |
1
|
1207 int c; |
|
1208 |
636
|
1209 while ((c = getc (fptr)) != EOF && isspace (c)) |
1
|
1210 ; // Don't count leading whitespace. |
|
1211 |
|
1212 if (c != EOF) |
|
1213 string_width++; |
|
1214 |
|
1215 for (;;) |
|
1216 { |
|
1217 c = getc (fptr); |
636
|
1218 if (c != EOF && ! isspace (c)) |
1
|
1219 string_width++; |
|
1220 else |
|
1221 break; |
|
1222 } |
|
1223 |
|
1224 fseek (fptr, original_position, SEEK_SET); |
|
1225 } |
|
1226 chars_from_fmt_str++; |
636
|
1227 char temp [string_width+1]; |
1
|
1228 fmt << *s << ends; |
|
1229 char *str = fmt.str (); |
|
1230 success = fscanf (fptr, str, temp); |
|
1231 delete [] str; |
636
|
1232 temp[string_width] = '\0'; |
628
|
1233 if (success > 0 && store_value) |
636
|
1234 values(fmt_arg_count++) = temp; |
1
|
1235 } |
|
1236 break; |
628
|
1237 |
1
|
1238 case 'c': |
|
1239 { |
|
1240 if (string_width < 1) |
|
1241 string_width = 1; |
|
1242 chars_from_fmt_str++; |
636
|
1243 char temp [string_width+1]; |
1
|
1244 memset (temp, '\0', string_width+1); |
|
1245 fmt << *s << ends; |
|
1246 char *str = fmt.str (); |
|
1247 success = fscanf (fptr, str, temp); |
|
1248 delete [] str; |
|
1249 temp[string_width] = '\0'; |
|
1250 if (success > 0 && store_value) |
636
|
1251 values(fmt_arg_count++) = temp; |
1
|
1252 } |
|
1253 break; |
628
|
1254 |
1
|
1255 default: |
|
1256 goto invalid_format; |
|
1257 } |
|
1258 |
368
|
1259 if (success > 0) |
1
|
1260 return chars_from_fmt_str; |
368
|
1261 else if (success == 0) |
218
|
1262 warning ("%s: invalid conversion", type); |
1
|
1263 else if (success == EOF) |
|
1264 { |
|
1265 if (strcmp (type, "fscanf") == 0) |
218
|
1266 warning ("%s: end of file reached before final conversion", type); |
1
|
1267 else if (strcmp (type, "sscanf") == 0) |
218
|
1268 warning ("%s: end of string reached before final conversion", type); |
1
|
1269 else if (strcmp (type, "scanf") == 0) |
218
|
1270 warning ("%s: end of input reached before final conversion", type); |
1
|
1271 } |
|
1272 else |
|
1273 { |
|
1274 invalid_format: |
218
|
1275 warning ("%s: invalid format", type); |
1
|
1276 } |
|
1277 |
|
1278 return -1; |
|
1279 } |
|
1280 |
761
|
1281 // Formatted reading from a file. |
|
1282 |
1181
|
1283 static Octave_object |
506
|
1284 do_scanf (const char *type, const Octave_object& args, int nargout) |
1
|
1285 { |
497
|
1286 Octave_object retval; |
529
|
1287 char *scanf_fmt = 0; |
|
1288 char *tmp_file = 0; |
1
|
1289 int tmp_file_open = 0; |
529
|
1290 FILE *fptr = 0; |
240
|
1291 file_info file; |
1
|
1292 |
|
1293 fmt_arg_count = 0; |
|
1294 |
|
1295 if (strcmp (type, "scanf") != 0) |
|
1296 { |
712
|
1297 scanf_fmt = args(1).string_value (); |
636
|
1298 |
|
1299 if (error_state) |
1
|
1300 { |
|
1301 error ("%s: format must be a string", type); |
|
1302 return retval; |
|
1303 } |
|
1304 } |
|
1305 |
|
1306 int doing_fscanf = (strcmp (type, "fscanf") == 0); |
|
1307 |
|
1308 if (doing_fscanf) |
|
1309 { |
712
|
1310 Pix p = file_io_get_file (args(0), "r", type); |
368
|
1311 |
529
|
1312 if (! p) |
368
|
1313 return retval; |
1
|
1314 |
|
1315 file = file_list (p); |
|
1316 |
|
1317 if (strcmp (file.mode (), "w") == 0 || strcmp (file.mode (), "a") == 0) |
|
1318 { |
|
1319 error ("%s: this file is opened for writing only", type); |
|
1320 return retval; |
|
1321 } |
|
1322 |
|
1323 fptr = file.fptr (); |
|
1324 } |
|
1325 |
712
|
1326 if ((! fptr && args(0).is_string ()) |
368
|
1327 || (doing_fscanf && file.number () == 0)) |
1
|
1328 { |
|
1329 char *string; |
|
1330 |
|
1331 if (strcmp (type, "scanf") == 0) |
712
|
1332 scanf_fmt = args(0).string_value (); |
1
|
1333 |
|
1334 if (strcmp (type, "scanf") == 0 |
|
1335 || (doing_fscanf && file.number () == 0)) |
|
1336 { |
870
|
1337 // XXX FIXME XXX -- this should probably be possible for more than |
|
1338 // just stdin/stdout pairs, using a list of output streams to flush. |
|
1339 // The list could be created with a function like iostream's tie(). |
|
1340 |
|
1341 flush_output_to_pager (); |
|
1342 |
1
|
1343 string = gnu_readline (""); |
870
|
1344 |
1
|
1345 if (string && *string) |
|
1346 maybe_save_history (string); |
|
1347 } |
|
1348 else |
712
|
1349 string = args(0).string_value (); |
1
|
1350 |
637
|
1351 tmp_file = octave_tmp_file_name (); |
1
|
1352 |
|
1353 fptr = fopen (tmp_file, "w+"); |
529
|
1354 if (! fptr) |
1
|
1355 { |
|
1356 error ("%s: error opening temporary file", type); |
|
1357 return retval; |
|
1358 } |
|
1359 tmp_file_open = 1; |
|
1360 unlink (tmp_file); |
|
1361 |
529
|
1362 if (! string) |
776
|
1363 { |
|
1364 error ("%s: no string to scan", type); |
|
1365 return retval; |
|
1366 } |
1
|
1367 |
|
1368 int success = fputs (string, fptr); |
|
1369 fflush (fptr); |
|
1370 rewind (fptr); |
|
1371 |
|
1372 if (success < 0) |
|
1373 { |
|
1374 error ("%s: trouble writing temporary file", type); |
|
1375 fclose (fptr); |
|
1376 return retval; |
|
1377 } |
|
1378 } |
|
1379 else if (! doing_fscanf) |
|
1380 { |
|
1381 error ("%s: first argument must be a string", type); |
|
1382 return retval; |
|
1383 } |
|
1384 |
|
1385 // Scan scanf_fmt for % escapes and assign the arguments. |
|
1386 |
636
|
1387 retval.resize (nargout); |
1
|
1388 |
|
1389 char *ptr = scanf_fmt; |
|
1390 |
|
1391 for (;;) |
|
1392 { |
|
1393 ostrstream fmt; |
|
1394 char c; |
|
1395 while ((c = *ptr++) != '\0' && c != '%') |
|
1396 fmt << c; |
|
1397 |
|
1398 if (c == '\0') |
|
1399 break; |
|
1400 |
|
1401 if (*ptr == '%') |
|
1402 { |
|
1403 ptr++; |
|
1404 fmt << c; |
|
1405 continue; |
|
1406 } |
|
1407 |
|
1408 // We must be looking at a format specifier. Extract it or fail. |
|
1409 |
368
|
1410 int status = process_scanf_format (ptr, fmt, type, nargout, |
|
1411 fptr, retval); |
1
|
1412 |
|
1413 if (status < 0) |
|
1414 { |
|
1415 if (fmt_arg_count == 0) |
497
|
1416 retval.resize (0); |
1
|
1417 break; |
|
1418 } |
|
1419 |
|
1420 ptr += status; |
|
1421 } |
|
1422 |
|
1423 if (tmp_file_open) |
|
1424 fclose (fptr); |
|
1425 |
|
1426 return retval; |
|
1427 } |
|
1428 |
1181
|
1429 DEFUN ("fscanf", Ffscanf, Sfscanf, 2, -1, |
|
1430 "[A, B, C, ...] = fscanf (FILENAME or FILENUM, FORMAT)") |
|
1431 { |
|
1432 Octave_object retval; |
|
1433 |
|
1434 int nargin = args.length (); |
|
1435 |
|
1436 if (nargin != 1 && nargin != 2) |
|
1437 print_usage ("fscanf"); |
|
1438 else |
|
1439 retval = do_scanf ("fscanf", args, nargout); |
|
1440 |
|
1441 return retval; |
|
1442 } |
|
1443 |
|
1444 // Formatted reading. |
|
1445 |
|
1446 DEFUN ("scanf", Fscanf, Sscanf, 1, -1, |
|
1447 "[A, B, C, ...] = scanf (FORMAT)") |
|
1448 { |
|
1449 Octave_object retval; |
|
1450 |
|
1451 int nargin = args.length (); |
|
1452 |
|
1453 if (nargin != 1) |
|
1454 print_usage ("scanf"); |
|
1455 else |
|
1456 retval = do_scanf ("scanf", args, nargout); |
|
1457 |
|
1458 return retval; |
|
1459 } |
|
1460 |
|
1461 // Formatted reading from a string. |
|
1462 |
|
1463 DEFUN ("sscanf", Fsscanf, Ssscanf, 2, -1, |
|
1464 "[A, B, C, ...] = sscanf (STRING, FORMAT)") |
|
1465 { |
|
1466 Octave_object retval; |
|
1467 |
|
1468 int nargin = args.length (); |
|
1469 |
|
1470 if (nargin != 2) |
|
1471 print_usage ("sscanf"); |
|
1472 else |
|
1473 retval = do_scanf ("sscanf", args, nargout); |
|
1474 |
|
1475 return retval; |
|
1476 } |
|
1477 |
761
|
1478 // Find out how many elements are left to read. |
|
1479 |
444
|
1480 static long |
471
|
1481 num_items_remaining (FILE *fptr, char *type) |
444
|
1482 { |
471
|
1483 size_t size; |
|
1484 |
|
1485 if (strcasecmp (type, "uchar") == 0) |
|
1486 size = sizeof (u_char); |
|
1487 else if (strcasecmp (type, "char") == 0) |
|
1488 size = sizeof (char); |
|
1489 else if (strcasecmp (type, "short") == 0) |
|
1490 size = sizeof (short); |
|
1491 else if (strcasecmp (type, "ushort") == 0) |
|
1492 size = sizeof (u_short); |
|
1493 else if (strcasecmp (type, "int") == 0) |
|
1494 size = sizeof (int); |
|
1495 else if (strcasecmp (type, "uint") == 0) |
|
1496 size = sizeof (u_int); |
|
1497 else if (strcasecmp (type, "long") == 0) |
|
1498 size = sizeof (long); |
|
1499 else if (strcasecmp (type, "ulong") == 0) |
|
1500 size = sizeof (u_long); |
|
1501 else if (strcasecmp (type, "float") == 0) |
|
1502 size = sizeof (float); |
|
1503 else if (strcasecmp (type, "double") == 0) |
|
1504 size = sizeof (double); |
|
1505 else |
|
1506 return 0; |
|
1507 |
444
|
1508 long curr_pos = ftell (fptr); |
|
1509 |
|
1510 fseek (fptr, 0, SEEK_END); |
|
1511 long end_of_file = ftell (fptr); |
|
1512 |
471
|
1513 fseek (fptr, curr_pos, SEEK_SET); |
444
|
1514 |
|
1515 long len = end_of_file - curr_pos; |
|
1516 |
471
|
1517 return len / size; |
444
|
1518 } |
|
1519 |
761
|
1520 // Read binary data from a file. |
|
1521 // |
|
1522 // [data, count] = fread (fid, size, 'precision') |
|
1523 // |
|
1524 // fid : the file id from fopen |
|
1525 // size : the size of the matrix or vector or scaler to read |
|
1526 // |
|
1527 // n : reads n elements of a column vector |
|
1528 // inf : reads to the end of file (default) |
|
1529 // [m, n] : reads enough elements to fill the matrix |
|
1530 // the number of columns can be inf |
|
1531 // |
|
1532 // precision : type of the element. Can be: |
|
1533 // |
|
1534 // char, uchar, schar, short, ushort, int, uint, |
|
1535 // long, ulong, float, double |
|
1536 // |
|
1537 // Default is uchar. |
|
1538 // |
|
1539 // data : output data |
|
1540 // count : number of elements read |
|
1541 |
1181
|
1542 static Octave_object |
506
|
1543 fread_internal (const Octave_object& args, int nargout) |
444
|
1544 { |
497
|
1545 Octave_object retval; |
444
|
1546 |
506
|
1547 int nargin = args.length (); |
|
1548 |
712
|
1549 Pix p = file_io_get_file (args(0), "r", "fread"); |
444
|
1550 |
529
|
1551 if (! p) |
444
|
1552 return retval; |
|
1553 |
|
1554 // Get type and number of bytes per element to read. |
|
1555 char *prec = "uchar"; |
712
|
1556 if (nargin > 2) |
444
|
1557 { |
712
|
1558 prec = args(2).string_value (); |
636
|
1559 |
|
1560 if (error_state) |
444
|
1561 { |
|
1562 error ("fread: precision must be a specified as a string"); |
|
1563 return retval; |
|
1564 } |
|
1565 } |
|
1566 |
471
|
1567 // Get file info. |
444
|
1568 |
|
1569 file_info file = file_list (p); |
471
|
1570 |
|
1571 FILE *fptr = file.fptr (); |
444
|
1572 |
|
1573 // Set up matrix to read into. If specified in arguments use that |
|
1574 // number, otherwise read everyting left in file. |
|
1575 |
471
|
1576 double dnr = 0.0; |
|
1577 double dnc = 0.0; |
|
1578 int nr; |
|
1579 int nc; |
444
|
1580 |
712
|
1581 if (nargin > 1) |
444
|
1582 { |
712
|
1583 if (args(1).is_scalar_type ()) |
444
|
1584 { |
712
|
1585 dnr = args(1).double_value (); |
636
|
1586 |
|
1587 if (error_state) |
|
1588 return retval; |
|
1589 |
471
|
1590 dnc = 1.0; |
444
|
1591 } |
636
|
1592 else |
444
|
1593 { |
712
|
1594 ColumnVector tmp = args(1).vector_value (); |
444
|
1595 |
636
|
1596 if (error_state || tmp.length () != 2) |
471
|
1597 { |
|
1598 error ("fread: invalid size specification\n"); |
|
1599 return retval; |
|
1600 } |
636
|
1601 |
|
1602 dnr = tmp.elem (0); |
|
1603 dnc = tmp.elem (1); |
471
|
1604 } |
|
1605 |
|
1606 if ((xisinf (dnr)) && (xisinf (dnc))) |
444
|
1607 { |
471
|
1608 error ("fread: number of rows and columns cannot both be infinite"); |
444
|
1609 return retval; |
|
1610 } |
|
1611 |
471
|
1612 if (xisinf (dnr)) |
|
1613 { |
1086
|
1614 if (xisnan (dnc)) |
|
1615 { |
|
1616 error ("fread: NaN invalid as the number of columns"); |
|
1617 return retval; |
|
1618 } |
|
1619 else |
|
1620 { |
|
1621 nc = NINT (dnc); |
|
1622 int n = num_items_remaining (fptr, prec); |
|
1623 nr = n / nc; |
|
1624 if (n > nr * nc) |
|
1625 nr++; |
|
1626 } |
471
|
1627 } |
|
1628 else if (xisinf (dnc)) |
|
1629 { |
1086
|
1630 if (xisnan (dnr)) |
|
1631 { |
|
1632 error ("fread: NaN invalid as the number of rows"); |
|
1633 return retval; |
|
1634 } |
|
1635 else |
|
1636 { |
|
1637 nr = NINT (dnr); |
|
1638 int n = num_items_remaining (fptr, prec); |
|
1639 nc = n / nr; |
|
1640 if (n > nc * nr) |
|
1641 nc++; |
|
1642 } |
471
|
1643 } |
|
1644 else |
|
1645 { |
1086
|
1646 if (xisnan (dnr)) |
|
1647 { |
|
1648 error ("fread: NaN invalid as the number of rows"); |
|
1649 return retval; |
|
1650 } |
|
1651 else |
|
1652 nr = NINT (dnr); |
|
1653 |
|
1654 if (xisnan (dnc)) |
|
1655 { |
|
1656 error ("fread: NaN invalid as the number of columns"); |
|
1657 return retval; |
|
1658 } |
|
1659 else |
|
1660 nc = NINT (dnc); |
471
|
1661 } |
444
|
1662 } |
|
1663 else |
|
1664 { |
|
1665 // No size parameter, read what's left of the file. |
471
|
1666 nc = 1; |
|
1667 int n = num_items_remaining (fptr, prec); |
|
1668 nr = n / nc; |
|
1669 if (n > nr * nc) |
|
1670 nr++; |
444
|
1671 } |
|
1672 |
|
1673 Matrix m (nr, nc, octave_NaN); |
|
1674 |
|
1675 // Read data. |
|
1676 |
471
|
1677 int count = m.read (fptr, prec); |
444
|
1678 |
|
1679 if (nargout > 1) |
636
|
1680 retval(1) = (double) count; |
444
|
1681 |
636
|
1682 retval(0) = m; |
444
|
1683 |
|
1684 return retval; |
|
1685 } |
|
1686 |
1181
|
1687 DEFUN ("fread", Ffread, Sfread, 3, 2, |
|
1688 "[DATA, COUNT] = fread (FILENUM, SIZE, PRECISION)\n\ |
529
|
1689 \n\ |
1181
|
1690 Reads data in binary form of type PRECISION from a file.\n\ |
529
|
1691 \n\ |
|
1692 FILENUM : file number from fopen\n\ |
1181
|
1693 SIZE : size specification for the Data matrix\n\ |
529
|
1694 PRECISION : type of data to read, valid types are\n\ |
|
1695 \n\ |
|
1696 'char', 'schar', 'short', 'int', 'long', 'float'\n\ |
|
1697 'double', 'uchar', 'ushort', 'uint', 'ulong'\n\ |
|
1698 \n\ |
1181
|
1699 DATA : matrix in which the data is stored\n\ |
|
1700 COUNT : number of elements read") |
529
|
1701 { |
|
1702 Octave_object retval; |
|
1703 |
|
1704 int nargin = args.length (); |
|
1705 |
1181
|
1706 if (nargin < 1 || nargin > 3) |
|
1707 print_usage ("fread"); |
529
|
1708 else |
1181
|
1709 retval = fread_internal (args, nargout); |
529
|
1710 |
|
1711 return retval; |
|
1712 } |
|
1713 |
761
|
1714 // Write binary data to a file. |
|
1715 // |
|
1716 // count = fwrite (fid, data, 'precision') |
|
1717 // |
|
1718 // fid : file id from fopen |
|
1719 // Data : data to be written |
|
1720 // precision : type of output element. Can be: |
|
1721 // |
|
1722 // char, uchar, schar, short, ushort, int, uint, |
|
1723 // long, float, double |
|
1724 // |
|
1725 // Default is uchar. |
|
1726 // |
|
1727 // count : the number of elements written |
|
1728 |
1181
|
1729 static Octave_object |
506
|
1730 fwrite_internal (const Octave_object& args, int nargout) |
444
|
1731 { |
497
|
1732 Octave_object retval; |
444
|
1733 |
506
|
1734 int nargin = args.length (); |
|
1735 |
761
|
1736 Pix p = file_io_get_file (args(0), "a+", "fwrite"); |
444
|
1737 |
529
|
1738 if (! p) |
444
|
1739 return retval; |
|
1740 |
|
1741 // Get type and number of bytes per element to read. |
|
1742 char *prec = "uchar"; |
712
|
1743 if (nargin > 2) |
444
|
1744 { |
761
|
1745 prec = args(2).string_value (); |
636
|
1746 |
|
1747 if (error_state) |
444
|
1748 { |
|
1749 error ("fwrite: precision must be a specified as a string"); |
|
1750 return retval; |
|
1751 } |
|
1752 } |
|
1753 |
|
1754 file_info file = file_list (p); |
|
1755 |
761
|
1756 Matrix m = args(1).matrix_value (); |
444
|
1757 |
636
|
1758 if (! error_state) |
|
1759 { |
|
1760 int count = m.write (file.fptr (), prec); |
444
|
1761 |
636
|
1762 retval(0) = (double) count; |
|
1763 } |
444
|
1764 |
|
1765 return retval; |
|
1766 } |
|
1767 |
1181
|
1768 DEFUN ("fwrite", Ffwrite, Sfwrite, 3, 1, |
|
1769 "COUNT = fwrite (FILENUM, DATA, PRECISION)\n\ |
|
1770 \n\ |
|
1771 Writes data to a file in binary form of size PRECISION\n\ |
|
1772 \n\ |
|
1773 FILENUM : file number from fopen\n\ |
|
1774 DATA : matrix of elements to be written\n\ |
|
1775 PRECISION : type of data to read, valid types are\n\ |
|
1776 \n\ |
|
1777 'char', 'schar', 'short', 'int', 'long', 'float'\n\ |
|
1778 'double', 'uchar', 'ushort', 'uint', 'ulong'\n\ |
|
1779 \n\ |
|
1780 COUNT : number of elements written") |
|
1781 { |
|
1782 Octave_object retval; |
|
1783 |
|
1784 int nargin = args.length (); |
|
1785 |
|
1786 if (nargin < 2 || nargin > 3) |
|
1787 print_usage ("fwrite"); |
|
1788 else |
|
1789 retval = fwrite_internal (args, nargout); |
|
1790 |
|
1791 return retval; |
|
1792 } |
|
1793 |
|
1794 // Check for an EOF condition on a file opened by fopen. |
|
1795 // |
|
1796 // eof = feof (fid) |
|
1797 // |
|
1798 // fid : file id from fopen |
|
1799 // eof : non zero for an end of file condition |
|
1800 |
|
1801 static Octave_object |
|
1802 feof_internal (const Octave_object& args, int nargout) |
|
1803 { |
|
1804 Octave_object retval; |
|
1805 |
|
1806 // Get file info. |
|
1807 Pix p = return_valid_file (args(0)); |
|
1808 |
|
1809 if (! p) |
|
1810 return retval; |
|
1811 |
|
1812 file_info file = file_list (p); |
|
1813 |
|
1814 retval(0) = (double) feof (file.fptr ()); |
|
1815 |
|
1816 return retval; |
|
1817 } |
|
1818 |
712
|
1819 DEFUN ("feof", Ffeof, Sfeof, 1, 1, |
529
|
1820 "ERROR = feof (FILENAME or FILENUM)\n\ |
|
1821 \n\ |
|
1822 Returns a non zero value for an end of file condition for the\n\ |
|
1823 file specified by FILENAME or FILENUM from fopen") |
|
1824 { |
|
1825 Octave_object retval; |
|
1826 |
|
1827 int nargin = args.length (); |
|
1828 |
712
|
1829 if (nargin != 1) |
529
|
1830 print_usage ("feof"); |
|
1831 else |
|
1832 retval = feof_internal (args, nargout); |
|
1833 |
|
1834 return retval; |
|
1835 } |
|
1836 |
1181
|
1837 // Check for an error condition on a file opened by fopen. |
761
|
1838 // |
1181
|
1839 // [message, errnum] = ferror (fid) |
761
|
1840 // |
1181
|
1841 // fid : file id from fopen |
|
1842 // message : system error message |
|
1843 // errnum : error number |
761
|
1844 |
1181
|
1845 static Octave_object |
|
1846 ferror_internal (const Octave_object& args, int nargout) |
444
|
1847 { |
497
|
1848 Octave_object retval; |
444
|
1849 |
|
1850 // Get file info. |
1049
|
1851 Pix p = return_valid_file (args(0)); |
444
|
1852 |
529
|
1853 if (! p) |
444
|
1854 return retval; |
|
1855 |
|
1856 file_info file = file_list (p); |
|
1857 |
1181
|
1858 int ierr = ferror (file.fptr ()); |
|
1859 |
|
1860 if (nargout > 1) |
|
1861 retval(1) = (double) ierr; |
|
1862 |
|
1863 retval(0) = strsave (strerror (ierr)); |
529
|
1864 |
|
1865 return retval; |
|
1866 } |
|
1867 |
712
|
1868 DEFUN ("ferror", Fferror, Sferror, 1, 1, |
529
|
1869 "ERROR = ferror (FILENAME or FILENUM)\n\ |
|
1870 \n\ |
|
1871 Returns a non zero value for an error condition on the\n\ |
|
1872 file specified by FILENAME or FILENUM from fopen") |
|
1873 { |
|
1874 Octave_object retval; |
|
1875 |
|
1876 int nargin = args.length (); |
|
1877 |
712
|
1878 if (nargin != 1) |
529
|
1879 print_usage ("ferror"); |
|
1880 else |
|
1881 retval = ferror_internal (args, nargout); |
444
|
1882 |
|
1883 return retval; |
|
1884 } |
|
1885 |
|
1886 /* |
1
|
1887 ;;; Local Variables: *** |
|
1888 ;;; mode: C++ *** |
|
1889 ;;; page-delimiter: "^/\\*" *** |
|
1890 ;;; End: *** |
|
1891 */ |