Mercurial > hg > octave-nkf
view src/oct-stream.cc @ 2554:f7e3d23f0a8f
[project @ 1996-11-21 01:41:57 by jwe]
author | jwe |
---|---|
date | Thu, 21 Nov 1996 01:43:06 +0000 |
parents | 3be97fe02051 |
children | 5c2be7c820ed |
line wrap: on
line source
/* Copyright (C) 1996 John W. Eaton This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <cstring> #include <iomanip.h> #include <strstream.h> #include "lo-ieee.h" #include "lo-mappers.h" #include "lo-utils.h" #include "str-vec.h" #include "error.h" #include "oct-stream.h" #include "utils.h" // Possible values for conv_err: // // 1 : not a real scalar // 2 : error extracting scalar value (should not happen) // 3 : value is NaN // 4 : value is not an integer static int convert_to_valid_int (const octave_value& tc, int& conv_err) { int retval = 0; conv_err = 0; if (tc.is_real_scalar ()) { double dval = tc.double_value (); if (! error_state) { if (! xisnan (dval)) { int ival = NINT (dval); if ((double) ival == dval) retval = ival; else conv_err = 4; } else conv_err = 3; } else conv_err = 2; } else conv_err = 1; return retval; } static int get_size (double d, const char *warn_for) { int retval = -1; if (! xisnan (d)) { if (! xisinf (d)) { if (d > 0.0) retval = NINT (d); else ::error ("%s: negative value invalid as size specification", warn_for); } else retval = -1; } else ::error ("%s: NaN is invalid as size specification", warn_for); return retval; } static void get_size (const Matrix& size, int& nr, int& nc, const char *warn_for) { nr = -1; nc = -1; double dnr = -1.0; double dnc = -1.0; if (size.rows () == 1 && size.cols () > 0) { dnr = size (0, 0); if (size.cols () == 2) dnc = size (0, 1); else if (size.cols () > 2) ::error ("%s: invalid size specification", warn_for); } else if (size.cols () == 1 && size.rows () > 0) { dnr = size (0, 0); if (size.rows () == 2) dnc = size (1, 0); else if (size.rows () > 2) ::error ("%s: invalid size specification", warn_for); } else ::error ("%s: invalid size specification", warn_for); if (! error_state) { nr = get_size (dnr, warn_for); if (! error_state && dnc > 0.0) nc = get_size (dnc, warn_for); } } scanf_format_list::scanf_format_list (const string& s) : nconv (0), curr_idx (0), list (16), buf (0) { int num_elts = 0; int n = s.length (); int i = 0; int width = 0; bool discard = false; char modifier = '\0'; char type = '\0'; bool have_more = true; while (i < n) { have_more = true; if (! buf) buf = new ostrstream (); if (s[i] == '%') { process_conversion (s, i, n, width, discard, type, modifier, num_elts); have_more = (buf != 0); } else { width = 0; discard = false; modifier = '\0'; type = '\0'; *buf << s[i++]; } if (nconv < 0) { have_more = false; break; } } if (have_more) add_elt_to_list (width, discard, type, modifier, num_elts); list.resize (num_elts); delete buf; } scanf_format_list::~scanf_format_list (void) { int n = list.length (); for (int i = 0; i < n; i++) { scanf_format_elt *elt = list (i); delete elt; } } void scanf_format_list::add_elt_to_list (int width, bool discard, char type, char modifier, int& num_elts) { if (buf) { *buf << ends; char *text = buf->str (); if (text) { if (*text) { scanf_format_elt *elt = new scanf_format_elt (text, width, discard, type, modifier); if (num_elts == list.length ()) list.resize (2 * num_elts); list (num_elts++) = elt; } else delete [] text; } delete buf; buf = 0; } } void scanf_format_list::process_conversion (const string& s, int& i, int n, int& width, bool& discard, char& type, char& modifier, int& num_elts) { width = 0; discard = false; modifier = '\0'; type = '\0'; *buf << s[i++]; bool have_width = false; while (i < n) { switch (s[i]) { case '*': if (discard) nconv = -1; else { discard = true; *buf << s[i++]; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (have_width) nconv = -1; else { char c = s[i++]; width = width * 10 + c - '0'; have_width = true; *buf << c; while (i < n && isdigit (s[i])) { c = s[i++]; width = width * 10 + c - '0'; *buf << c; } } break; case 'h': case 'l': case 'L': if (modifier != '\0') nconv = -1; else { modifier = s[i]; *buf << s[i++]; } break; case 'd': case 'i': case 'o': case 'u': case 'x': if (modifier == 'L') { nconv = -1; break; } goto fini; case 'e': case 'f': case 'g': if (modifier == 'h') { nconv = -1; break; } goto fini; case 'c': case 's': case 'p': case '%': case '[': if (modifier != '\0') { nconv = -1; break; } goto fini; fini: { if (finish_conversion (s, i, n, width, discard, type, modifier, num_elts) == 0) return; } break; default: nconv = -1; break; } if (nconv < 0) break; } nconv = -1; } int scanf_format_list::finish_conversion (const string& s, int& i, int n, int& width, bool discard, char& type, char modifier, int& num_elts) { int retval = 0; if (s[i] == '%') *buf << s[i++]; else { type = s[i]; if (s[i] == '[') { *buf << s[i++]; if (i < n) { if (s[i] == '^') { type = '^'; *buf << s[i++]; } else if (s[i] == ']') *buf << s[i++]; } while (i < n && s[i] != ']') *buf << s[i++]; if (i < n && s[i] == ']') *buf << s[i++]; if (s[i-1] != ']') retval = nconv = -1; } else *buf << s[i++]; nconv++; if (nconv > 0) add_elt_to_list (width, discard, type, modifier, num_elts); } return retval; } void scanf_format_list::printme (void) const { int n = list.length (); for (int i = 0; i < n; i++) { scanf_format_elt *elt = list (i); cerr << elt->width << "\t" << elt->discard << "\t" << elt->type << "\t" << elt->modifier << "\t" << undo_string_escapes (elt->text) << "\n"; } } bool scanf_format_list::all_character_conversions (void) { int n = list.length (); if (n > 0) { for (int i = 0; i < n; i++) { scanf_format_elt *elt = list (i); switch (elt->type) { case 'c': case 's': case 'p': case '%': case '[': break; default: return false; break; } } return true; } else return false; } bool scanf_format_list::all_numeric_conversions (void) { int n = list.length (); if (n > 0) { for (int i = 0; i < n; i++) { scanf_format_elt *elt = list (i); switch (elt->type) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'e': case 'f': case 'g': break; default: return false; break; } } return true; } else return false; } // Ugh again. printf_format_list::printf_format_list (const string& s) : nconv (0), curr_idx (0), list (16), buf (0) { int num_elts = 0; int n = s.length (); int i = 0; int args = 0; char modifier = '\0'; char type = '\0'; bool have_more = true; while (i < n) { have_more = true; if (! buf) buf = new ostrstream (); switch (s[i]) { case '%': process_conversion (s, i, n, args, type, modifier, num_elts); have_more = (buf != 0); break; default: args = 0; modifier = '\0'; type = '\0'; *buf << s[i++]; break; } if (nconv < 0) { have_more = false; break; } } if (have_more) add_elt_to_list (args, type, modifier, num_elts); list.resize (num_elts); delete buf; } printf_format_list::~printf_format_list (void) { int n = list.length (); for (int i = 0; i < n; i++) { printf_format_elt *elt = list (i); delete elt; } } void printf_format_list::add_elt_to_list (int args, char type, char modifier, int& num_elts) { if (buf) { *buf << ends; char *text = buf->str (); if (text) { if (*text) { printf_format_elt *elt = new printf_format_elt (text, args, type, modifier); if (num_elts == list.length ()) list.resize (2 * num_elts); list (num_elts++) = elt; } else delete [] text; } delete buf; buf = 0; } } void printf_format_list::process_conversion (const string& s, int& i, int n, int& args, char& modifier, char& type, int& num_elts) { args = 0; modifier = '\0'; type = '\0'; *buf << s[i++]; bool next = false; while (i < n) { switch (s[i]) { case '-': case '+': case ' ': case '0': case '#': *buf << s[i++]; break; default: next = true; break; } if (next) break; } if (i < n) { if (s[i] == '*') { args++; *buf << s[i++]; } else { while (i < n && isdigit (s[i])) *buf << s[i++]; } } if (i < n && s[i] == '.') { *buf << s[i++]; if (i < n) { if (s[i] == '*') { args++; *buf << s[i++]; } else { while (i < n && isdigit (s[i])) *buf << s[i++]; } } } if (i < n) { switch (s[i]) { case 'h': case 'l': case 'L': modifier = s[i]; *buf << s[i++]; break; default: break; } } if (i < n) finish_conversion (s, i, args, modifier, type, num_elts); else nconv = -1; } void printf_format_list::finish_conversion (const string& s, int& i, int args, char modifier, char& type, int& num_elts) { switch (s[i]) { case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': case 'c': if (modifier == 'L') { nconv = -1; break; } goto fini; case 'f': case 'e': case 'E': case 'g': case 'G': if (modifier == 'h' || modifier == 'l') { nconv = -1; break; } goto fini; case 's': case 'p': case '%': if (modifier != '\0') { nconv = -1; break; } goto fini; fini: if (s[i] == '%' && args == 0) *buf << s[i++]; else { if (s[i] != '%') args++; type = s[i]; *buf << s[i++]; add_elt_to_list (args, type, modifier, num_elts); nconv++; } break; default: nconv = -1; break; } } void printf_format_list::printme (void) const { int n = list.length (); for (int i = 0; i < n; i++) { printf_format_elt *elt = list (i); cerr << elt->args<< "\t" << elt->type << "\t" << elt->modifier << "\t" << undo_string_escapes (elt->text) << "\n"; } } void octave_base_stream::error (const string& msg) { fail = true; errmsg = msg; } void octave_base_stream::clear (void) { fail = false; errmsg = ""; } // Functions that are defined for all input streams (input streams // are those that define is). string octave_base_stream::do_gets (int max_len, bool& err, bool strip_newline, const char *fcn) { string retval; err = false; istream *isp = input_stream (); if (isp) { istream& is = *isp; // XXX FIXME XXX -- this should probably be converted to use // sstream when that is available. ostrstream buf; int c = 0; int count = 0; int newline_stripped = 0; while (is && (c = is.get ()) != EOF) { count++; if (c == '\n') { if (! strip_newline) buf << (char) c; else newline_stripped = 1; break; } else buf << (char) c; if (max_len > 0 && count == max_len) break; } if (is.fail ()) { err = true; string msg = fcn; msg.append (": read error"); error (msg); } else if (is.eof ()) { err = true; string msg = fcn; msg.append (": at end of file"); error (msg); } else { buf << ends; char *tmp = buf.str (); retval = tmp; delete [] tmp; } } else { err = true; invalid_operation (fcn, "reading"); } return retval; } string octave_base_stream::getl (int max_len, bool& err) { return do_gets (max_len, err, true, "fgetl"); } string octave_base_stream::gets (int max_len, bool& err) { return do_gets (max_len, err, false, "fgets"); } octave_value octave_base_stream::read (const Matrix& size, oct_data_conv::data_type dt, int skip, oct_mach_info::float_format flt_fmt, int& count) { Matrix retval; count = 0; istream *isp = input_stream (); if (isp) { istream& is = *isp; int nr = -1; int nc = -1; get_size (size, nr, nc, "fread"); if (! error_state) { if (flt_fmt == oct_mach_info::unknown) flt_fmt = float_format (); int tmp = retval.read (is, nr, nc, dt, skip, flt_fmt); if (tmp < 0) error ("fread: read error"); else count = tmp; } } else invalid_operation ("fread", "reading"); return retval; } #define do_scanf_conv(is, fmt, valptr, mval, data, idx, max_size, discard) \ do \ { \ is.scan (fmt, valptr); \ \ if (is) \ { \ if (idx == max_size && ! discard) \ { \ max_size *= 2; \ \ if (nr > 0) \ mval.resize (nr, max_size / nr, 0.0); \ else \ mval.resize (max_size, 1, 0.0); \ \ data = mval.fortran_vec (); \ } \ \ if (! discard) \ data[idx++] = *(valptr); \ } \ } \ while (0) octave_value octave_base_stream::do_scanf (scanf_format_list& fmt_list, int nr, int nc, int& count) { count = 0; octave_value retval = Matrix (); istream *isp = input_stream (); bool all_char_conv = fmt_list.all_character_conversions (); Matrix mval; double *data = 0; int max_size = 0; int final_nr = 0; int final_nc = 0; if (nr > 0) { if (nc > 0) { mval.resize (nr, nc, 0.0); data = mval.fortran_vec (); max_size = nr * nc; } else { mval.resize (nr, 32, 0.0); data = mval.fortran_vec (); max_size = nr * 32; } } else { mval.resize (32, 1, 0.0); data = mval.fortran_vec (); max_size = 32; } if (isp) { istream& is = *isp; const scanf_format_elt *elt = fmt_list.first (); ios::fmtflags flags = is.flags (); for (;;) { if (elt) { if (nr > 0 && nc > 0 && count == max_size) { final_nr = nr; final_nc = nc; break; } const char *fmt = elt->text; bool discard = elt->discard; switch (elt->type) { case '%': { int dummy; is.scan (fmt, &dummy); } break; case 'd': case 'i': case 'o': case 'u': case 'x': { int tmp; do_scanf_conv (is, fmt, &tmp, mval, data, count, max_size, discard); } break; case 'e': case 'f': case 'g': { if (elt->modifier == 'l') { double tmp; do_scanf_conv (is, fmt, &tmp, mval, data, count, max_size, discard); } else { float tmp; do_scanf_conv (is, fmt, &tmp, mval, data, count, max_size, discard); } } break; case 'c': is.unsetf (ios::skipws); // Fall through... case 's': { int len = strlen (fmt); char *tmp_fmt = new char [len+1]; strcpy (tmp_fmt, fmt); if (tmp_fmt[len-1] == 's') tmp_fmt[len-1] = 'c'; int width = elt->width ? elt->width : 1; char *tmp = new char [width+1]; is.scan (tmp_fmt, tmp); delete [] tmp_fmt; tmp[width] = '\0'; if (is) { int i = 0; if (! discard) { while (i < width && tmp[i] != '\0') { if (count == max_size) { max_size *= 2; if (nr > 0) mval.resize (nr, max_size / nr, 0.0); else mval.resize (max_size, 1, 0.0); data = mval.fortran_vec (); } data[count++] = tmp[i++]; } } } delete [] tmp; is.setf (flags); } break; case 'p': case '[': error ("fscanf: unsupported format specifier"); break; default: error ("fscanf: internal format error"); break; } if (! ok ()) { break; } else if (! is) { if (is.eof ()) { if (nr > 0) { if (count > nr) { final_nr = nr; final_nc = (count - 1) / nr + 1; } else { final_nr = count; final_nc = 1; } } else { final_nr = count; final_nc = 1; } } else { error ("fscanf: read error"); // XXX FIXME XXX -- is this the right thing to do? // What about other streams? if (name () == "stdin") { is.clear (); // Skip to end of line. bool err; do_gets (-1, err, false, "fscanf"); } } break; } } else { error ("fscanf: internal format error"); break; } elt = fmt_list.next (); } } if (ok ()) { mval.resize (final_nr, final_nc, 0.0); if (all_char_conv) { if (nr < 0) mval = mval.transpose (); retval = mval; retval = retval.convert_to_str (); } else retval = mval; } return retval; } octave_value octave_base_stream::scanf (const string& fmt, const Matrix& size, int& count) { octave_value retval = Matrix (); count = 0; istream *isp = input_stream (); if (isp) { istream& is = *isp; scanf_format_list fmt_list (fmt); switch (fmt_list.num_conversions ()) { case -1: ::error ("fscanf: invalid format specified"); break; case 0: { const scanf_format_elt *elt = fmt_list.first (); if (elt) { is.clear (); is.scan (elt->text); if (! is) { error ("fscanf: read error"); // XXX FIXME XXX -- is this the right thing to do? if (name () == "stdin") { is.clear (); // Skip to end of line. bool err; do_gets (-1, err, false, "fscanf"); } } } } break; default: { int nr = -1; int nc = -1; get_size (size, nr, nc, "fscanf"); if (! error_state) retval = do_scanf (fmt_list, nr, nc, count); } break; } } else invalid_operation ("fscanf", "writing"); return retval; } #define do_oscanf_num_conv(is, fmt, valptr) \ do \ { \ streambuf *isb = is.rdbuf (); \ \ if (isb->scan (fmt, valptr) > 0) \ { \ if (! discard && is) \ retval = (double) (*valptr); \ } \ else \ error ("fscanf: conversion failed"); \ } \ while (0) #define do_oscanf_str_conv(is, fmt, sptr, maxlen) \ do \ { \ streambuf *isb = is.rdbuf (); \ \ if (isb->scan (fmt, sptr) > 0) \ { \ if (! discard && is) \ { \ sptr[maxlen] = '\0'; \ retval = sptr; \ } \ } \ else \ error ("fscanf: conversion failed"); \ } \ while (0) octave_value octave_base_stream::do_oscanf (const scanf_format_elt *elt) { octave_value retval = Matrix (); istream *isp = input_stream (); if (isp) { istream& is = *isp; ios::fmtflags flags = is.flags (); if (elt) { const char *fmt = elt->text; bool discard = elt->discard; switch (elt->type) { case '%': { int dummy; is.scan (fmt, &dummy); } break; case 'd': case 'i': case 'o': case 'u': case 'x': { int tmp; do_oscanf_num_conv (is, fmt, &tmp); } break; case 'e': case 'f': case 'g': { if (elt->modifier == 'l') { double tmp; do_oscanf_num_conv (is, fmt, &tmp); } else { float tmp; do_oscanf_num_conv (is, fmt, &tmp); } } break; case 'c': { is.unsetf (ios::skipws); int width = elt->width ? elt->width : 1; char *tmp = new char[width + 1]; do_oscanf_str_conv (is, fmt, tmp, width); is.setf (flags); delete [] tmp; } break; case 's': { // XXX FIXME XXX -- this must be fixed! int width = elt->width ? elt->width : 65535; char *tmp = new char [width+1]; do_oscanf_str_conv (is, fmt, tmp, width); delete [] tmp; } break; case 'p': case '[': error ("fscanf: unsupported format specifier"); break; default: error ("fscanf: internal format error"); break; } } if (ok () && is.fail ()) { error ("fscanf: read error"); // XXX FIXME XXX -- is this the right thing to do? // What about other streams? if (name () == "stdin") { is.clear (); // Skip to end of line. bool err; do_gets (-1, err, false, "fscanf"); } } } return retval; } octave_value_list octave_base_stream::oscanf (const string& fmt) { octave_value_list retval; istream *isp = input_stream (); if (isp) { istream& is = *isp; scanf_format_list fmt_list (fmt); int nconv = fmt_list.num_conversions (); switch (nconv) { case -1: ::error ("fscanf: invalid format specified"); break; case 0: { const scanf_format_elt *elt = fmt_list.first (); if (elt) { is.clear (); is.scan (elt->text); if (! is) { error ("fscanf: read error"); // XXX FIXME XXX -- is this the right thing to do? // Maybe. We should probably also arrange to // flush the pending input prior to printing a // prompt. Or maybe just blow off scanf for stdin // like the MathWorks did. What about other streams? if (name () == "stdin") { is.clear (); // Skip to end of line. bool err; do_gets (-1, err, false, "fscanf"); } } } } break; default: { int len = fmt_list.length (); retval.resize (nconv, Matrix ()); const scanf_format_elt *elt = fmt_list.first (); for (int i = 0; i < nconv; i++) { retval (i) = do_oscanf (elt); if (! ok ()) break; elt = fmt_list.next (); } // Pick up any trailing stuff. if (ok () && len > nconv) do_oscanf (elt); } break; } } else invalid_operation ("fscanf", "writing"); return retval; } // Functions that are defined for all output streams (output streams // are those that define os). int octave_base_stream::flush (void) { int retval = -1; ostream *os = output_stream (); if (os) { os->flush (); if (os->good ()) retval = 0; } else invalid_operation ("fflush", "writing"); return retval; } int octave_base_stream::write (const octave_value& data, oct_data_conv::data_type dt, int skip, oct_mach_info::float_format flt_fmt) { int retval = -1; ostream *osp = output_stream (); if (osp) { ostream& os = *osp; Matrix mval = data.matrix_value (); if (! error_state) { if (flt_fmt == oct_mach_info::unknown) flt_fmt = float_format (); int tmp = mval.write (os, dt, skip, flt_fmt); if (tmp < 0) error ("fwrite: write error"); else retval = tmp; } } else invalid_operation ("fwrite", "writing"); return retval; } class printf_value_cache { public: enum state { ok, list_exhausted, conversion_error }; printf_value_cache (const octave_value_list& args) : values (args), val_idx (0), elt_idx (0), n_vals (values.length ()), n_elts (0), data (0), curr_state (ok) { } ~printf_value_cache (void) { } // Get the current value as a double and advance the internal pointer. double double_value (void); // Get the current value as an int and advance the internal pointer. int int_value (void); // Get the current value as a string and advance the internal pointer. string string_value (void); operator void* () const { return (curr_state == ok) ? (void *) -1 : (void *) 0; } bool no_more_values (void) { return curr_state == list_exhausted; } bool looking_at_string (void); private: const octave_value_list values; int val_idx; int elt_idx; int n_vals; int n_elts; const double *data; Matrix curr_val; state curr_state; // Must create value cache with values! printf_value_cache (void); // No copying! printf_value_cache (const printf_value_cache&); printf_value_cache& operator = (const printf_value_cache&); }; bool printf_value_cache::looking_at_string (void) { bool retval = false; int idx = -1; if (elt_idx == 0) idx = val_idx; else if (elt_idx >= n_elts) idx = val_idx + 1; if (idx >= 0 && idx < n_vals) { octave_value tmp_val = values (idx); retval = tmp_val.is_string () && tmp_val.rows () == 1; } return retval; } double printf_value_cache::double_value (void) { double retval = 0.0; while (val_idx < n_vals) { if (! data) { octave_value tmp_val = values (val_idx); curr_val = tmp_val.matrix_value (); if (! error_state) { elt_idx = 0; n_elts = curr_val.length (); data = curr_val.data (); } else { curr_state = conversion_error; break; } } if (elt_idx < n_elts) { return data[elt_idx++]; break; } else { val_idx++; data = 0; continue; } } curr_state = list_exhausted; return retval; } int printf_value_cache::int_value (void) { int retval = 0; double dval = double_value (); if (! error_state) { if (D_NINT (dval) == dval) retval = NINT (dval); else curr_state = conversion_error; } return retval; } string printf_value_cache::string_value (void) { string retval; if (looking_at_string ()) { if (elt_idx != 0) { val_idx++; elt_idx = 0; data = 0; } retval = values (val_idx++).string_value (); } else curr_state = conversion_error; return retval; } // Ugh again and again. #define do_printf_conv(os, fmt, nsa, sa_1, sa_2, have_arg, arg) \ do \ { \ switch (nsa) \ { \ case 2: \ if (have_arg) \ os.form (fmt, sa_1, sa_2, arg); \ else \ os.form (fmt, sa_1, sa_2); \ break; \ \ case 1: \ if (have_arg) \ os.form (fmt, sa_1, arg); \ else \ os.form (fmt, sa_1); \ break; \ \ case 0: \ if (have_arg) \ os.form (fmt, arg); \ else \ os.form (fmt); \ break; \ \ default: \ ::error ("fprintf: internal error handling format"); \ break; \ } \ } \ while (0) int octave_base_stream::do_printf (printf_format_list& fmt_list, const octave_value_list& args) { int retval = -1; ostream *osp = output_stream (); if (osp) { ostream& os = *osp; const printf_format_elt *elt = fmt_list.first (); printf_value_cache val_cache (args); for (;;) { if (elt) { int args = elt->args; int nsa = args; int doing_percent = elt->type == '%'; if (args > 0 && ! doing_percent) nsa--; int sa_1 = 0; int sa_2 = 0; if (nsa > 0) { sa_1 = val_cache.int_value (); if (! val_cache) break; else { if (nsa > 1) { sa_2 = val_cache.int_value (); if (! val_cache) break; } } } const char *fmt = elt->text; if (doing_percent || args == 0) do_printf_conv (os, fmt, nsa, sa_1, sa_2, 0, 0.0); else { if (elt->type == 's' && val_cache.looking_at_string ()) { string val = val_cache.string_value (); if (val_cache) do_printf_conv (os, fmt, nsa, sa_1, sa_2, 1, val.c_str ()); else break; } else { double val = val_cache.double_value (); if (val_cache) { switch (elt->type) { case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': case 'c': { if (elt->modifier == 'l') do_printf_conv (os, fmt, nsa, sa_1, sa_2, 1, (long) val); else do_printf_conv (os, fmt, nsa, sa_1, sa_2, 1, (int) val); } break; case 'f': case 'e': case 'E': case 'g': case 'G': do_printf_conv (os, fmt, nsa, sa_1, sa_2, 1, val); break; default: error ("fprintf: invalid format specifier"); return -1; break; } } else break; } if (val_cache.no_more_values ()) { retval = 0; break; } } if (os) retval += nsa + (doing_percent ? 0 : 1); else { error ("fprintf: write error"); retval = -1; break; } } else { ::error ("fprintf: internal error handling format"); retval = -1; break; } elt = fmt_list.next (); } } return retval; } int octave_base_stream::printf (const string& fmt, const octave_value_list& args) { int retval = -1; ostream *osp = output_stream (); if (osp) { ostream& os = *osp; printf_format_list fmt_list (fmt); switch (fmt_list.num_conversions ()) { case -1: ::error ("fprintf: invalid format specified"); break; case 0: { const printf_format_elt *elt = fmt_list.first (); if (elt) { os.form (elt->text); if (os) retval = 0; else error ("fprintf: write error"); } } break; default: { if (args.length () == 0) ::error ("fprintf: no arguments available for specified format"); else retval = do_printf (fmt_list, args); } break; } } else invalid_operation ("fprintf", "writing"); return retval; } int octave_base_stream::puts (const string& s) { int retval = -1; ostream *osp = output_stream (); if (osp) { ostream& os = *osp; os << s; if (os) { // XXX FIXME XXX -- why does this seem to be necessary? // Without it, output from a loop like // // for i = 1:100, fputs (stdout, "foo\n"); endfor // // doesn't seem to go to the pager immediately. os.flush (); if (os) retval = 0; else error ("fputs: write error"); } else error ("fputs: write error"); } else invalid_operation ("fputs", "writing"); return retval; } int octave_base_stream::rewind (void) { return seek (0, ios::beg); } // Return current error message for this stream. string octave_base_stream::error (bool clear_err, int& err_num) { err_num = fail ? -1 : 0; string tmp = errmsg; if (clear_err) clear (); return tmp; } void octave_base_stream::invalid_operation (const char *op, const char *rw) { string msg = op; msg.append (": stream not open for "); msg.append (rw); error (msg); } int octave_stream::flush (void) { int retval = -1; if (stream_ok ("fflush")) retval = rep->flush (); return retval; } string octave_stream::getl (int max_len, bool& err) { string retval; if (stream_ok ("getl")) retval = rep->getl (max_len, err); return retval; } string octave_stream::getl (const octave_value& tc_max_len, bool& err) { string retval; err = false; int conv_err = 0; int max_len = convert_to_valid_int (tc_max_len, conv_err); if (conv_err || max_len < 0) { err = true; ::error ("fgetl: invalid maximum length specified"); } else retval = getl (max_len, err); return retval; } string octave_stream::gets (int max_len, bool& err) { string retval; if (stream_ok ("fgets")) retval = rep->gets (max_len, err); return retval; } string octave_stream::gets (const octave_value& tc_max_len, bool& err) { string retval; err = false; int conv_err = 0; int max_len = convert_to_valid_int (tc_max_len, conv_err); if (conv_err || max_len < 0) { err = true; ::error ("fgets: invalid maximum length specified"); } else retval = gets (max_len, err); return retval; } int octave_stream::seek (streampos offset, ios::seek_dir origin) { int retval = -1; if (stream_ok ("fseek")) retval = rep->seek (offset, origin); return retval; } int octave_stream::seek (const octave_value& tc_offset, const octave_value& tc_origin) { int retval = -1; int conv_err = 0; int xoffset = convert_to_valid_int (tc_offset, conv_err); if (! conv_err) { ios::seek_dir origin = ios::beg; if (tc_origin.is_string ()) { string xorigin = tc_origin.string_value (); if (xorigin == "bof") origin = ios::beg; else if (xorigin == "cof") origin = ios::cur; else if (xorigin == "eof") origin = ios::end; else conv_err = -1; } else { int xorigin = convert_to_valid_int (tc_origin, conv_err); if (! conv_err) { if (xorigin == -1) origin = ios::beg; else if (xorigin == 0) origin = ios::cur; else if (xorigin == 1) origin = ios::end; else conv_err = -1; } } if (! conv_err) retval = seek (xoffset, origin); else error ("fseek: invalid value for origin"); } else error ("fseek: invalid value for offset"); return retval; } long octave_stream::tell (void) const { long retval = -1; if (stream_ok ("tell")) retval = rep->tell (); return retval; } int octave_stream::rewind (void) { int retval = -1; if (stream_ok ("frewind")) retval = rep->rewind (); return retval; } octave_value octave_stream::read (const Matrix& size, oct_data_conv::data_type dt, int skip, oct_mach_info::float_format flt_fmt, int& count) { octave_value retval; if (stream_ok ("fread")) retval = rep->read (size, dt, skip, flt_fmt, count); return retval; } int octave_stream::write (const octave_value& data, oct_data_conv::data_type dt, int skip, oct_mach_info::float_format flt_fmt) { int retval = -1; if (stream_ok ("fwrite")) retval = rep->write (data, dt, skip, flt_fmt); return retval; } octave_value octave_stream::scanf (const string& fmt, const Matrix& size, int& count) { octave_value retval; if (stream_ok ("fscanf")) retval = rep->scanf (fmt, size, count); return retval; } octave_value_list octave_stream::oscanf (const string& fmt) { octave_value_list retval; if (stream_ok ("fscanf")) retval = rep->oscanf (fmt); return retval; } int octave_stream::printf (const string& fmt, const octave_value_list& args) { int retval = -1; if (stream_ok ("fprintf")) retval = rep->printf (fmt, args); return retval; } int octave_stream::puts (const string& s) { int retval = -1; if (stream_ok ("fputs")) retval = rep->puts (s); return retval; } // XXX FIXME XXX -- maybe this should work for string arrays too. int octave_stream::puts (const octave_value& tc_s) { int retval = -1; if (tc_s.is_string ()) { string s = tc_s.string_value (); retval = rep->puts (s); } else error ("fputs: argument must be a string"); return retval; } bool octave_stream::eof (void) const { int retval = -1; if (stream_ok ("feof")) retval = rep->eof (); return retval; } string octave_stream::error (bool clear, int& err_num) { string retval; if (stream_ok ("ferror", false)) retval = rep->error (clear, err_num); return retval; } string octave_stream::name (void) { string retval; if (stream_ok ("name")) retval = rep->name (); return retval; } int octave_stream::mode (void) { int retval = 0; if (stream_ok ("mode")) retval = rep->mode (); return retval; } oct_mach_info::float_format octave_stream::float_format (void) { oct_mach_info::float_format retval = oct_mach_info::unknown; if (stream_ok ("float_format")) retval = rep->float_format (); return retval; } string octave_stream::mode_as_string (int mode) { string retval = "???"; switch (mode) { case ios::in: retval = "r"; break; case ios::out: case ios::out | ios::trunc: retval = "w"; break; case ios::out | ios::app: retval = "a"; break; case ios::in | ios::out: retval = "r+"; break; case ios::in | ios::out | ios::trunc: retval = "w+"; break; case ios::in | ios::out | ios::app: retval = "a+"; break; case ios::in | ios::bin: retval = "rb"; break; case ios::out | ios::bin: case ios::out | ios::trunc | ios::bin: retval = "wb"; break; case ios::out | ios::app | ios::bin: retval = "ab"; break; case ios::in | ios::out | ios::bin: retval = "r+b"; break; case ios::in | ios::out | ios::trunc | ios::bin: retval = "w+b"; break; case ios::in | ios::out | ios::app | ios::bin: retval = "a+b"; break; default: break; } return retval; } void octave_stream::invalid_stream_error (const char *op) const { ::error ("%s: attempt to use invalid I/O stream", op); } octave_stream_list *octave_stream_list::instance = 0; int octave_stream_list::do_insert (octave_base_stream *obs) { int retval = -1; if (obs) { octave_stream *os = new octave_stream (obs); // Insert item in first open slot, increasing size of list if // necessary. for (int i = 0; i < curr_len; i++) { octave_stream *tmp = list (i); if (! tmp) { list (i) = os; retval = i; break; } } if (retval < 0) { int total_len = list.length (); if (curr_len == total_len) list.resize (total_len * 2); list (curr_len) = os; retval = curr_len; curr_len++; } } else ::error ("octave_stream_list: attempt to insert invalid stream"); return retval; } int octave_stream_list::insert (octave_base_stream *obs) { int retval = -1; if (! instance) instance = new octave_stream_list (); if (instance) retval = instance->do_insert (obs); else panic_impossible (); return retval; } octave_stream * octave_stream_list::do_lookup (int fid) const { octave_stream *retval = 0; if (fid >= 0 && fid < curr_len) retval = list (fid); return retval; } octave_stream * octave_stream_list::do_lookup (const octave_value& fid) const { octave_stream *retval = 0; int i = get_file_number (fid); if (! error_state) retval = do_lookup (i); return retval; } octave_stream * octave_stream_list::lookup (int fid) { octave_stream *retval = 0; if (instance) retval = instance->do_lookup (fid); return retval; } octave_stream * octave_stream_list::lookup (const octave_value& fid) { octave_stream *retval = 0; if (instance) retval = instance->do_lookup (fid); return retval; } int octave_stream_list::do_remove (int fid) { int retval = -1; // Can't remove stdin (cin), stdout (cout), or stderr (cerr). if (fid > 2 && fid < curr_len) { octave_stream *os = list (fid); if (os) { delete os; list (fid) = 0; retval = 0; } } return retval; } int octave_stream_list::do_remove (const octave_value& fid) { int retval = -1; int i = get_file_number (fid); if (! error_state) retval = do_remove (i); return retval; } int octave_stream_list::remove (int fid) { int retval = -1; if (instance) retval = instance->do_remove (fid); return retval; } int octave_stream_list::remove (const octave_value& fid) { int retval = -1; if (instance) retval = instance->do_remove (fid); return retval; } void octave_stream_list::do_clear (void) { // Do flush stdout and stderr. list (0) -> flush (); list (1) -> flush (); // But don't delete them or stdin. for (int i = 3; i < curr_len; i++) { octave_stream *os = list (i); delete os; list (i) = 0; } } void octave_stream_list::clear (void) { if (instance) instance->do_clear (); } string_vector octave_stream_list::do_get_info (int fid) const { string_vector retval; octave_stream *os = do_lookup (fid); if (os) { retval.resize (3); retval(0) = os->name (); retval(1) = octave_stream::mode_as_string (os->mode ()); retval(2) = oct_mach_info::float_format_as_string (os->float_format ()); } else ::error ("invalid file id"); return retval; } string_vector octave_stream_list::do_get_info (const octave_value& fid) const { string_vector retval; int conv_err = 0; int int_fid = convert_to_valid_int (fid, conv_err); if (! conv_err) retval = do_get_info (int_fid); else ::error ("file id must be valid integer"); return retval; } string_vector octave_stream_list::get_info (int fid) { string_vector retval; if (instance) retval = instance->do_get_info (fid); return retval; } string_vector octave_stream_list::get_info (const octave_value& fid) { string_vector retval; if (instance) retval = instance->do_get_info (fid); return retval; } string octave_stream_list::do_list_open_files (void) const { string retval; // XXX FIXME XXX -- this should probably be converted to use sstream // when that is available. ostrstream buf; buf << "\n" << " number mode arch name\n" << " ------ ---- ---- ----\n"; for (int i = 0; i < curr_len; i++) { octave_stream *os = list (i); if (os) { string mode = octave_stream::mode_as_string (os->mode ()); string arch = oct_mach_info::float_format_as_string (os->float_format ()); string name = os->name (); buf.form (" %4d %-3s %-9s %s\n", i, mode.c_str (), arch.c_str (), name.c_str ()); } } buf << "\n" << ends; char *tmp = buf.str (); retval = tmp; delete [] tmp; return retval; } string octave_stream_list::list_open_files (void) { string retval; if (instance) retval = instance->do_list_open_files (); return retval; } octave_value octave_stream_list::do_open_file_numbers (void) const { Matrix retval (1, curr_len, 0.0); int num_open = 0; // Skip stdin, stdout, and stderr. for (int i = 3; i < curr_len; i++) { if (list (i)) retval (0, num_open++) = i; } retval.resize ((num_open > 0), num_open); return retval; } octave_value octave_stream_list::open_file_numbers (void) { octave_value retval; if (instance) retval = instance->do_open_file_numbers (); return retval; } int octave_stream_list::get_file_number (const octave_value& fid) const { int retval = -1; if (fid.is_string ()) { string nm = fid.string_value (); // stdin (cin), stdout (cout), and stderr (cerr) are unnamed. for (int i = 3; i < curr_len; i++) { octave_stream *os = list (i); if (os && os->name () == nm) { retval = i; break; } } } else { int conv_err = 0; int int_fid = convert_to_valid_int (fid, conv_err); if (conv_err) ::error ("file id must be a string or integer value"); else retval = int_fid; } return retval; } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */