comparison src/file-io.cc @ 1:78fd87e624cb

[project @ 1993-08-08 01:13:40 by jwe] Initial revision
author jwe
date Sun, 08 Aug 1993 01:13:40 +0000
parents
children 74d6f5fe70a1
comparison
equal deleted inserted replaced
0:22412e3a4641 1:78fd87e624cb
1 // file-io.cc -*- C++ -*-
2 /*
3
4 Copyright (C) 1993 John W. Eaton
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
26 #ifdef __GNUG__
27 #pragma implementation
28 #endif
29
30 #include <DLList.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <strstream.h>
36 #include <ctype.h>
37
38 #include "statdefs.h"
39 #include "file-io.h"
40 #include "input.h"
41 #include "octave-hist.h"
42 #include "tree-const.h"
43 #include "error.h"
44 #include "utils.h"
45 #include "pager.h"
46
47 // keeps a count of how many files are open and in the file list
48 static int file_count = 0;
49
50 // keeps a count of args sent to printf or scanf
51 static int fmt_arg_count = 0;
52
53 class File_info
54 {
55 public:
56 File_info (void);
57 File_info (int num, char *nm, FILE *t, char *md);
58 File_info (const File_info& f);
59
60 File_info& operator = (const File_info& f);
61
62 ~File_info (void);
63
64 int number (void) const;
65 char *name (void) const;
66 FILE *fptr (void) const;
67 char *mode (void) const;
68
69 private:
70 int _number;
71 char *_name;
72 FILE *_fptr;
73 char *_mode;
74 };
75
76 File_info::File_info (void)
77 {
78 _number = -1;
79 _name = (char *) NULL;
80 _fptr = (FILE *) NULL;
81 _mode = (char *) NULL;
82 }
83
84 File_info::File_info (const File_info& f)
85 {
86 _number = f._number;
87 _name = strsave (f._name);
88 _fptr = f._fptr;
89 _mode = strsave (f._mode);
90 }
91
92 File_info&
93 File_info::operator = (const File_info& f)
94 {
95 _number = f._number;
96 _name = strsave (f._name);
97 _fptr = f._fptr;
98 _mode = strsave (f._mode);
99
100 return *this;
101 }
102
103 File_info::~File_info (void)
104 {
105 delete [] _name;
106 delete [] _mode;
107 }
108
109 File_info::File_info (int n, char *nm, FILE *t, char *md)
110 {
111 _number = n;
112 _name = strsave (nm);
113 _fptr = t;
114 _mode = strsave (md);
115 }
116
117 int
118 File_info::number (void) const
119 {
120 return _number;
121 }
122
123 char *
124 File_info::name (void) const
125 {
126 return _name;
127 }
128
129 FILE *
130 File_info::fptr (void) const
131 {
132 return _fptr;
133 }
134
135 char *
136 File_info::mode (void) const
137 {
138 return _mode;
139 }
140
141
142 // double linked list containing relevant information about open files
143 static DLList <File_info> file_list;
144
145 void
146 initialize_file_io ()
147 {
148 File_info _stdin (0, "stdin", stdin, "r");
149 File_info _stdout (1, "stdout", stdout, "w");
150 File_info _stderr (2, "stderr", stderr, "w");
151
152 file_list.append (_stdin);
153 file_list.append (_stdout);
154 file_list.append (_stderr);
155
156 file_count = 3;
157 }
158
159 Pix
160 return_valid_file (tree_constant& arg)
161 {
162 if (arg.is_string_type ())
163 {
164 Pix p = file_list.first ();
165 File_info file;
166 for (int i = 0; i < file_count; i++)
167 {
168 char *file_name = arg.string_value ();
169 file = file_list (p);
170 if (strcmp (file.name (), file_name) == 0)
171 return p;
172 file_list.next (p);
173 }
174 }
175 else if (arg.is_scalar_type ())
176 {
177 double file_num = arg.double_value ();
178 if ((double) NINT (file_num) != file_num)
179 error ("file number not an integer value");
180 else
181 {
182 Pix p = file_list.first ();
183 File_info file;
184 for (int i = 0; i < file_count; i++)
185 {
186 file = file_list (p);
187 if (file.number () == file_num)
188 return p;
189 file_list.next (p);
190 }
191 error ("no file with that number");
192 }
193 }
194 else
195 error ("inapproriate file specifier");
196
197 return (Pix) NULL;
198 }
199
200 static Pix
201 fopen_file_for_user (tree_constant& arg, char *mode)
202 {
203 char *file_name = arg.string_value ();
204
205 FILE *file_ptr = fopen (file_name, mode);
206 if (file_ptr != (FILE *) NULL)
207 {
208 File_info file (++file_count, file_name, file_ptr, mode);
209 file_list.append (file);
210
211 Pix p = file_list.first ();
212 File_info file_from_list;
213
214 for (int i = 0; i < file_count; i++)
215 {
216 file_from_list = file_list (p);
217 if (strcmp (file_from_list.name (), file_name) == 0)
218 return p;
219 file_list.next (p);
220 }
221 }
222
223 error ("problems automatically opening file for user");
224 return (Pix) NULL;
225 }
226
227
228 tree_constant *
229 fclose_internal (tree_constant *args)
230 {
231 tree_constant *retval = NULL_TREE_CONST;
232
233 Pix p = return_valid_file (args[1]);
234
235 if (p == (Pix) NULL)
236 return retval;
237
238 File_info file = file_list (p);
239
240 if (file.number () < 3)
241 {
242 warning ("fclose: can't close stdin, stdout, or stderr!");
243 return retval;
244 }
245
246 int success = fclose (file.fptr ());
247 file_list.del (p);
248 file_count--;
249
250 retval = new tree_constant[2];
251 if (success == 0)
252 retval[0] = tree_constant (1.0); // succeeded
253 else
254 {
255 error ("fclose: error on closing file");
256 retval[0] = tree_constant (0.0); // failed
257 }
258
259 return retval;
260 }
261
262 tree_constant *
263 fflush_internal (tree_constant *args)
264 {
265 tree_constant *retval = NULL_TREE_CONST;
266
267 Pix p = return_valid_file (args[1]);
268
269 if (p == (Pix) NULL)
270 return retval;
271
272 File_info file = file_list (p);
273
274 if (strcmp (file.mode (), "r") == 0)
275 {
276 warning ("can't flush an input stream");
277 return retval;
278 }
279
280 int success = 0;
281 if (file.number () == 1)
282 flush_output_to_pager ();
283 else
284 success = fflush (file.fptr ());
285
286 retval = new tree_constant[2];
287 if (success == 0)
288 retval[0] = tree_constant (1.0); // succeeded
289 else
290 {
291 error ("fflush: write error");
292 retval[0] = tree_constant (0.0); // failed
293 }
294
295 return retval;
296 }
297
298 static int
299 valid_mode (char *mode)
300 {
301 if (mode != (char *) NULL)
302 {
303 char m = mode[0];
304 if (m == 'r' || m == 'w' || m == 'a')
305 {
306 m = mode[1];
307 return (m == '\0' || (m == '+' && mode[2] == '\0'));
308 }
309 }
310 return 0;
311 }
312
313 tree_constant *
314 fgets_internal (tree_constant *args, int nargout)
315 {
316 tree_constant *retval = NULL_TREE_CONST;
317
318 Pix p = return_valid_file (args[1]);
319
320 if (p == (Pix) NULL)
321 {
322 if (args[1].is_string_type ())
323 {
324 struct stat buffer;
325 char *name = args[1].string_value ();
326 if (stat (name, &buffer) == 0
327 && (buffer.st_mode & S_IFREG) == S_IFREG)
328 {
329 p = fopen_file_for_user (args[1], "r");
330 }
331 else
332 {
333 error ("fgets: file dosen't exist");
334 return retval;
335 }
336 }
337 else
338 return retval;
339 }
340
341 int length = 0;
342
343 if (args[2].is_scalar_type ())
344 {
345 length = (int) args[2].double_value ();
346 if ((double) NINT (length) != length)
347 {
348 error ("fgets: length not an integer value");
349 return retval;
350 }
351 }
352
353 char string[length+1];
354 File_info file = file_list (p);
355 char *success = fgets (string, length+1, file.fptr ());
356
357 if (success == (char *) NULL)
358 {
359 retval = new tree_constant[2];
360 retval[0] = tree_constant (-1.0);
361 return retval;
362 }
363
364 if (nargout == 2)
365 {
366 retval = new tree_constant[3];
367 retval[1] = tree_constant ((double) strlen (string));
368 }
369 else
370 retval = new tree_constant[2];
371
372 retval[0] = tree_constant (string);
373
374 return retval;
375 }
376
377 tree_constant *
378 fopen_internal (tree_constant *args)
379 {
380 tree_constant *retval = NULL_TREE_CONST;
381 Pix p;
382
383 if (! args[1].is_string_type ())
384 {
385 error ("fopen: file name must be a string");
386 return retval;
387 }
388
389 p = return_valid_file (args[1]);
390
391 if (p != (Pix) NULL)
392 {
393 File_info file = file_list (p);
394
395 retval = new tree_constant[2];
396 retval[0] = tree_constant ((double) file.number ());
397
398 return retval;
399 }
400
401 if (! args[2].is_string_type ())
402 {
403 error ("fopen: mode must be a string");
404 return retval;
405 }
406
407 char *name = args[1].string_value ();
408 char *mode = args[2].string_value ();
409
410 if (! valid_mode (mode))
411 {
412 error ("fopen: invalid mode");
413 return retval;
414 }
415
416 struct stat buffer;
417 if (stat (name, &buffer) == 0 && (buffer.st_mode & S_IFDIR) == S_IFDIR)
418 {
419 error ("fopen: can't open directory");
420 return retval;
421 }
422
423 FILE *file_ptr = fopen (name, mode);
424
425 if (file_ptr == (FILE *) NULL)
426 {
427 error ("fopen: file does not exist");
428 return retval;
429 }
430
431 int number = file_count++;
432
433 File_info file (number, name, file_ptr, mode);
434 file_list.append (file);
435
436 retval = new tree_constant[2];
437 retval[0] = tree_constant ((double) number);
438
439 return retval;
440 }
441
442 tree_constant *
443 freport_internal ()
444 {
445 tree_constant *retval = NULL_TREE_CONST;
446 Pix p = file_list.first ();
447
448 ostrstream output_buf;
449
450 output_buf << "\n number mode name\n\n";
451 for (int i = 0; i < file_count; i++)
452 {
453 File_info file = file_list (p);
454 output_buf.form ("%7d%6s %s\n", file.number (), file.mode (),
455 file.name ());
456 file_list.next (p);
457 }
458
459 output_buf << "\n" << ends;
460 maybe_page_output (output_buf);
461
462 return retval;
463 }
464
465 tree_constant *
466 frewind_internal (tree_constant *args)
467 {
468 tree_constant *retval = NULL_TREE_CONST;
469
470 Pix p = return_valid_file (args[1]);
471 if (p == (Pix) NULL)
472 p = fopen_file_for_user (args[1], "a+");
473
474 File_info file = file_list (p);
475 rewind (file.fptr ());
476
477 return retval;
478 }
479
480 tree_constant *
481 fseek_internal (tree_constant *args, int nargin)
482 {
483 tree_constant *retval = NULL_TREE_CONST;
484
485 Pix p = return_valid_file (args[1]);
486
487 if (p == (Pix) NULL)
488 p = fopen_file_for_user (args[1], "a+");
489
490 long origin = SEEK_SET;
491 long offset = 0;
492 if (args[2].is_scalar_type ())
493 {
494 offset = (long) args[2].double_value ();
495 if ((double) NINT (offset) != offset)
496 {
497 error ("fseek: offset not an integer value");
498 return retval;
499 }
500 }
501
502 if (nargin == 4 && args[3].is_scalar_type ())
503 {
504 origin = (long) args[3].double_value ();
505 if (origin == -1)
506 origin = SEEK_CUR;
507 else if (origin == -2)
508 origin = SEEK_END;
509 else
510 {
511 if ((double) NINT (origin) != origin)
512 {
513 error ("fseek: origin not an integer value");
514 return retval;
515 }
516 }
517 }
518
519 File_info file = file_list (p);
520 int success = fseek (file.fptr (), offset, origin);
521 retval = new tree_constant[2];
522
523 if (success == 0)
524 retval[0] = tree_constant (1.0); // succeeded
525 else
526 {
527 error ("fseek: file error");
528 retval[0] = tree_constant (0.0); // failed
529 }
530
531 return retval;
532 }
533
534 tree_constant *
535 ftell_internal (tree_constant *args)
536 {
537 tree_constant *retval = NULL_TREE_CONST;
538 Pix p = return_valid_file (args[1]);
539
540 if (p == (Pix) NULL)
541 p = fopen_file_for_user (args[1], "a+");
542
543 File_info file = file_list (p);
544 long offset = ftell (file.fptr ());
545 retval = new tree_constant[2];
546 retval[0] = tree_constant ((double) offset);
547
548 if (offset == -1L)
549 error ("ftell: write error");
550
551 return retval;
552 }
553
554 void
555 close_files ()
556 {
557 Pix p = file_list.first ();
558
559 for (int i = 0; i < file_count; i++)
560 {
561 File_info file = file_list (p);
562 if (i > 2) // do not close stdin, stdout, stderr!
563 {
564 int success = fclose (file.fptr ());
565 if (success != 0)
566 error ("closing %s", file.name ());
567 }
568 file_list.del (p);
569 }
570 }
571
572 static int
573 process_printf_format (char *s, tree_constant *args, ostrstream& sb,
574 char *type, int nargin)
575 {
576 ostrstream fmt;
577
578 fmt << "%"; // do_printf() already blew past this one...
579
580 tree_constant_rep::constant_type arg_type;
581
582 int chars_from_fmt_str = 0;
583
584 again:
585 switch (*s)
586 {
587 case '+': case '-': case ' ': case '0': case '#':
588 chars_from_fmt_str++;
589 fmt << *s++;
590 goto again;
591
592 case '\0':
593 goto invalid_format;
594
595 default:
596 break;
597 }
598
599 if (*s == '*')
600 {
601 if (fmt_arg_count >= nargin)
602 {
603 message (type, "not enough arguments");
604 return -1;
605 }
606
607 if (args[fmt_arg_count].const_type ()
608 != tree_constant_rep::scalar_constant)
609 {
610 message (type, "`*' must be replaced by an integer");
611 return -1;
612 }
613
614 fmt << (int) (args[fmt_arg_count++].double_value ());
615 s++;
616 chars_from_fmt_str++;
617 }
618 else
619 {
620 while (*s != '\0' && isdigit (*s))
621 {
622 chars_from_fmt_str++;
623 fmt << *s++;
624 }
625 }
626
627 if (*s == '\0')
628 goto invalid_format;
629
630 if (*s == '.')
631 {
632 chars_from_fmt_str++;
633 fmt << *s++;
634 }
635
636 if (*s == '*')
637 {
638 if (*(s-1) == '*')
639 goto invalid_format;
640
641 if (fmt_arg_count >= nargin)
642 {
643 message (type, "not enough arguments");
644 return -1;
645 }
646
647 if (args[fmt_arg_count].const_type ()
648 != tree_constant_rep::scalar_constant)
649 {
650 message (type, "`*' must be replaced by an integer");
651 return -1;
652 }
653
654 fmt << (int) (args[fmt_arg_count++].double_value ());
655 s++;
656 chars_from_fmt_str++;
657 }
658 else
659 {
660 while (*s != '\0' && isdigit (*s))
661 {
662 chars_from_fmt_str++;
663 fmt << *s++;
664 }
665 }
666
667 if (*s == '\0')
668 goto invalid_format;
669
670 if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
671 {
672 chars_from_fmt_str++;
673 fmt << *s++;
674 }
675
676 if (*s == '\0')
677 goto invalid_format;
678
679 if (fmt_arg_count >= nargin)
680 {
681 message (type, "not enough arguments");
682 return -1;
683 }
684
685 arg_type = args[fmt_arg_count].const_type ();
686
687 switch (*s)
688 {
689 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
690
691 if (arg_type != tree_constant_rep::scalar_constant)
692 goto invalid_conversion;
693 else
694 {
695 chars_from_fmt_str++;
696 fmt << *s << ends;
697 double d = args[fmt_arg_count++].double_value ();
698 if ((int) d != d)
699 goto invalid_conversion;
700 else
701 {
702 char *s = fmt.str ();
703 sb.form (s, (int) d);
704 delete [] s;
705 return chars_from_fmt_str;
706 }
707 }
708
709 case 'e': case 'E': case 'f': case 'g': case 'G':
710
711 if (arg_type != tree_constant_rep::scalar_constant)
712 goto invalid_conversion;
713 else
714 {
715 chars_from_fmt_str++;
716 fmt << *s << ends;
717 char *s = fmt.str ();
718 sb.form (s, args[fmt_arg_count++].double_value ());
719 delete [] s;
720 return chars_from_fmt_str;
721 }
722
723 case 's':
724
725 if (arg_type != tree_constant_rep::string_constant)
726 goto invalid_conversion;
727 else
728 {
729 chars_from_fmt_str++;
730 fmt << *s << ends;
731 char *s = fmt.str ();
732 sb.form (s, args[fmt_arg_count++].string_value ());
733 delete [] s;
734 return chars_from_fmt_str;
735 }
736
737 case 'c':
738
739 if (arg_type != tree_constant_rep::string_constant)
740 goto invalid_conversion;
741 else
742 {
743 chars_from_fmt_str++;
744 fmt << *s << ends;
745 char *str = args[fmt_arg_count++].string_value ();
746 if (strlen (str) != 1)
747 goto invalid_conversion;
748 else
749 {
750 char *s = fmt.str ();
751 sb.form (s, *str);
752 delete [] s;
753 return chars_from_fmt_str;
754 }
755 }
756
757 default:
758 goto invalid_format;
759 }
760
761 invalid_conversion:
762 message (type, "invalid conversion");
763 return -1;
764
765 invalid_format:
766 message (type, "invalid format");
767 return -1;
768 }
769
770
771 tree_constant *
772 do_printf (char *type, tree_constant *args, int nargin, int nargout)
773 {
774 tree_constant *retval = NULL_TREE_CONST;
775 fmt_arg_count = 1;
776 char *fmt;
777 File_info file;
778
779 if (strcmp (type, "fprintf") == 0)
780 {
781 Pix p;
782
783 if (args[2].is_string_type ())
784 {
785 fmt = args[2].string_value ();
786 fmt_arg_count++;
787 }
788 else
789 {
790 error ("%s: format must be a string", type);
791 return retval;
792 }
793
794 if (args[1].is_scalar_type ())
795 {
796 p = return_valid_file (args[1]);
797 if (p == (Pix) NULL)
798 return retval;
799 }
800 else if (args[1].is_string_type ())
801 {
802 p = return_valid_file (args[1]);
803 if (p == (Pix) NULL)
804 p = fopen_file_for_user (args[1], "a+");
805 }
806 else
807 {
808 error ("%s: illegal file specifier", type);
809 return retval;
810 }
811
812 file = file_list (p);
813 if (file.mode () == "r")
814 {
815 error ("%s: file is read only", type);
816 return retval;
817 }
818 fmt = args[2].string_value ();
819 fmt_arg_count++;
820 }
821 else if (args[1].is_string_type ())
822 {
823 fmt = args[1].string_value ();
824 fmt_arg_count++;
825 }
826 else
827 {
828 error ("%s: invalid format string", type);
829 return retval;
830 }
831
832 // Scan fmt for % escapes and print out the arguments.
833
834 ostrstream output_buf;
835
836 char *ptr = fmt;
837
838 for (;;)
839 {
840 char c;
841 while ((c = *ptr++) != '\0' && c != '%')
842 output_buf << c;
843
844 if (c == '\0')
845 break;
846
847 if (*ptr == '%')
848 {
849 ptr++;
850 output_buf << c;
851 continue;
852 }
853
854 // We must be looking at a format specifier. Extract it or fail.
855
856
857 int status = process_printf_format (ptr, args, output_buf, type,
858 nargin);
859
860 if (status < 0)
861 return retval;
862
863 ptr += status;
864 }
865
866 output_buf << ends;
867 if (strcmp (type, "printf") == 0
868 || (strcmp (type, "fprintf") == 0 && file.number () == 1))
869 {
870 maybe_page_output (output_buf);
871 }
872 else if (strcmp (type, "fprintf") == 0)
873 {
874 char *msg = output_buf.str ();
875 int success = fputs (msg, file.fptr ());
876 if (success == EOF)
877 error ("%s: writing to file", type);
878 delete [] msg;
879 }
880 else if (strcmp (type, "sprintf") == 0)
881 {
882 retval = new tree_constant [2];
883 char *msg = output_buf.str ();
884 retval[0] = tree_constant (msg);
885 delete [] msg;
886 }
887
888 return retval;
889 }
890
891 static int
892 process_scanf_format (char *s, tree_constant *args, ostrstream& fmt,
893 char *type, int nargout, FILE* fptr,
894 tree_constant *values)
895 {
896 fmt << "%";
897
898 tree_constant_rep::constant_type arg_type;
899
900 int chars_from_fmt_str = 0;
901 int store_value = 1;
902 int string_width = -1;
903 int success = 1;
904
905 if (*s == '*')
906 {
907 store_value = 0;
908 s++;
909 chars_from_fmt_str++;
910 }
911
912 if (isdigit (*s))
913 {
914 ostrstream str_number;
915 while (*s != '\0' && isdigit (*s))
916 {
917 chars_from_fmt_str++;
918 str_number << *s;
919 fmt << *s++;
920 }
921 str_number << ends;
922 char *number = str_number.str ();
923 string_width = atoi (number);
924 delete [] number;
925 }
926
927 if (*s == '\0')
928 goto invalid_format;
929
930 if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
931 {
932 chars_from_fmt_str++;
933 s++;
934 }
935
936 if (*s == '\0')
937 goto invalid_format;
938
939 if (fmt_arg_count >= nargout && store_value)
940 {
941 message (type, "not enough arguments");
942 return -1;
943 }
944
945 arg_type = args[fmt_arg_count].const_type ();
946
947 switch (*s)
948 {
949 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
950 {
951 chars_from_fmt_str++;
952 fmt << *s << ends;
953 int temp;
954 char *str = fmt.str ();
955 success = fscanf (fptr, str, &temp);
956 delete [] str;
957 if (success > 0 && store_value)
958 values[fmt_arg_count++] = tree_constant ((double) temp);
959 }
960 break;
961 case 'e': case 'E': case 'f': case 'g': case 'G':
962 {
963 chars_from_fmt_str++;
964 fmt << 'l' << *s << ends;
965 double temp;
966 char *str = fmt.str ();
967 success = fscanf (fptr, str, &temp);
968 delete [] str;
969 if (success > 0 && store_value)
970 values[fmt_arg_count++] = tree_constant (temp);
971 }
972 break;
973 case 's':
974 {
975 if (string_width < 1)
976 {
977 string_width = 0;
978 long original_position = ftell (fptr);
979 int c;
980
981 while ((c = getc (fptr)) != EOF
982 && (c == ' ' || c == '\n' || c != '\t'))
983 ; // Don't count leading whitespace.
984
985 if (c != EOF)
986 string_width++;
987
988 for (;;)
989 {
990 c = getc (fptr);
991 if (c != EOF && c != ' ' && c != '\n' && c != '\t')
992 string_width++;
993 else
994 break;
995 }
996
997 fseek (fptr, original_position, SEEK_SET);
998 }
999 chars_from_fmt_str++;
1000 char temp[string_width+1];
1001 fmt << *s << ends;
1002 char *str = fmt.str ();
1003 success = fscanf (fptr, str, temp);
1004 delete [] str;
1005 if (success && store_value)
1006 values[fmt_arg_count++] = tree_constant (temp);
1007 }
1008 break;
1009 case 'c':
1010 {
1011 if (string_width < 1)
1012 string_width = 1;
1013 chars_from_fmt_str++;
1014 char temp[string_width+1];
1015 memset (temp, '\0', string_width+1);
1016 fmt << *s << ends;
1017 char *str = fmt.str ();
1018 success = fscanf (fptr, str, temp);
1019 delete [] str;
1020 temp[string_width] = '\0';
1021 if (success > 0 && store_value)
1022 values[fmt_arg_count++] = tree_constant (temp);
1023 }
1024 break;
1025 default:
1026 goto invalid_format;
1027 }
1028
1029 if (success > 0 || (success == 0 && store_value == 0))
1030 return chars_from_fmt_str;
1031
1032 if (success == 0)
1033 message (type, "invalid conversion");
1034 else if (success == EOF)
1035 {
1036 if (strcmp (type, "fscanf") == 0)
1037 message (type, "end of file reached before final conversion");
1038 else if (strcmp (type, "sscanf") == 0)
1039 message (type, "end of string reached before final conversion");
1040 else if (strcmp (type, "scanf") == 0)
1041 message (type, "end of input reached before final conversion");
1042 }
1043 else
1044 {
1045 invalid_format:
1046 message (type, "invalid format");
1047 }
1048
1049 return -1;
1050 }
1051
1052 tree_constant *
1053 do_scanf (char *type, tree_constant *args, int nargin, int nargout)
1054 {
1055 tree_constant *retval = NULL_TREE_CONST;
1056 char *scanf_fmt = (char *) NULL;
1057 char *tmp_file = (char *) NULL;
1058 int tmp_file_open = 0;
1059 FILE *fptr = (FILE *) NULL;
1060 File_info file;
1061
1062 fmt_arg_count = 0;
1063
1064 if (strcmp (type, "scanf") != 0)
1065 {
1066 if ( args[2].is_string_type ())
1067 scanf_fmt = args[2].string_value ();
1068 else
1069 {
1070 error ("%s: format must be a string", type);
1071 return retval;
1072 }
1073 }
1074
1075 int doing_fscanf = (strcmp (type, "fscanf") == 0);
1076
1077 if (doing_fscanf)
1078 {
1079 Pix p;
1080 if (args[1].is_scalar_type ()
1081 || args[1].is_string_type ())
1082 {
1083 p = return_valid_file (args[1]);
1084 if (p == (Pix) NULL)
1085 return retval;
1086 }
1087 else
1088 {
1089 error ("%s: illegal file specifier", type);
1090 return retval;
1091 }
1092
1093 file = file_list (p);
1094
1095 if (strcmp (file.mode (), "w") == 0 || strcmp (file.mode (), "a") == 0)
1096 {
1097 error ("%s: this file is opened for writing only", type);
1098 return retval;
1099 }
1100
1101 fptr = file.fptr ();
1102 }
1103
1104 if (args[1].is_string_type () || (doing_fscanf && file.number () == 0))
1105 {
1106 char *string;
1107
1108 if (strcmp (type, "scanf") == 0)
1109 scanf_fmt = args[1].string_value ();
1110
1111 if (strcmp (type, "scanf") == 0
1112 || (doing_fscanf && file.number () == 0))
1113 {
1114 string = gnu_readline ("");
1115 if (string && *string)
1116 maybe_save_history (string);
1117 }
1118 else
1119 string = args[1].string_value ();
1120
1121 tmp_file = tmpnam ((char *) NULL);
1122
1123 fptr = fopen (tmp_file, "w+");
1124 if (fptr == (FILE *) NULL)
1125 {
1126 error ("%s: error opening temporary file", type);
1127 return retval;
1128 }
1129 tmp_file_open = 1;
1130 unlink (tmp_file);
1131
1132 if (string == (char *) NULL)
1133 panic_impossible ();
1134
1135 int success = fputs (string, fptr);
1136 fflush (fptr);
1137 rewind (fptr);
1138
1139 if (success < 0)
1140 {
1141 error ("%s: trouble writing temporary file", type);
1142 fclose (fptr);
1143 return retval;
1144 }
1145 }
1146 else if (! doing_fscanf)
1147 {
1148 error ("%s: first argument must be a string", type);
1149 return retval;
1150 }
1151
1152 // Scan scanf_fmt for % escapes and assign the arguments.
1153
1154 retval = new tree_constant[nargout+1];
1155
1156 char *ptr = scanf_fmt;
1157
1158 for (;;)
1159 {
1160 ostrstream fmt;
1161 char c;
1162 while ((c = *ptr++) != '\0' && c != '%')
1163 fmt << c;
1164
1165 if (c == '\0')
1166 break;
1167
1168 if (*ptr == '%')
1169 {
1170 ptr++;
1171 fmt << c;
1172 continue;
1173 }
1174
1175 // We must be looking at a format specifier. Extract it or fail.
1176
1177 int status = process_scanf_format (ptr, args, fmt, type,
1178 nargout, fptr, retval);
1179
1180 if (status < 0)
1181 {
1182 if (fmt_arg_count == 0)
1183 {
1184 delete [] retval;
1185 retval = NULL_TREE_CONST;
1186 }
1187 break;
1188 }
1189
1190 ptr += status;
1191 }
1192
1193 if (tmp_file_open)
1194 fclose (fptr);
1195
1196 return retval;
1197 }
1198
1199 /*
1200 ;;; Local Variables: ***
1201 ;;; mode: C++ ***
1202 ;;; page-delimiter: "^/\\*" ***
1203 ;;; End: ***
1204 */