ls-mat-ascii.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cfloat>
00028 #include <cstring>
00029 #include <cctype>
00030 
00031 #include <fstream>
00032 #include <iomanip>
00033 #include <iostream>
00034 #include <sstream>
00035 #include <string>
00036 
00037 #include "byte-swap.h"
00038 #include "data-conv.h"
00039 #include "file-ops.h"
00040 #include "glob-match.h"
00041 #include "lo-mappers.h"
00042 #include "mach-info.h"
00043 #include "oct-env.h"
00044 #include "oct-time.h"
00045 #include "quit.h"
00046 #include "str-vec.h"
00047 
00048 #include "Cell.h"
00049 #include "defun.h"
00050 #include "error.h"
00051 #include "gripes.h"
00052 #include "lex.h"
00053 #include "load-save.h"
00054 #include "ls-ascii-helper.h"
00055 #include "ls-mat-ascii.h"
00056 #include "oct-obj.h"
00057 #include "oct-map.h"
00058 #include "ov-cell.h"
00059 #include "pager.h"
00060 #include "pt-exp.h"
00061 #include "sysdep.h"
00062 #include "unwind-prot.h"
00063 #include "utils.h"
00064 #include "variables.h"
00065 #include "version.h"
00066 #include "dMatrix.h"
00067 
00068 static std::string
00069 get_mat_data_input_line (std::istream& is)
00070 {
00071   std::string retval;
00072 
00073   bool have_data = false;
00074 
00075   do
00076     {
00077       retval = "";
00078 
00079       char c;
00080       while (is.get (c))
00081         {
00082           if (c == '\n' || c == '\r')
00083             {
00084               is.putback (c);
00085               skip_preceeding_newline (is);
00086               break;
00087             }
00088 
00089           if (c == '%' || c == '#')
00090             {
00091               skip_until_newline (is, false);
00092               break;
00093             }
00094 
00095           if (! is.eof ())
00096             {
00097               if (! have_data && c != ' ' && c != '\t')
00098                 have_data = true;
00099 
00100               retval += c;
00101             }
00102         }
00103     }
00104   while (! (have_data || is.eof ()));
00105 
00106   return retval;
00107 }
00108 
00109 static void
00110 get_lines_and_columns (std::istream& is, const std::string& filename, octave_idx_type& nr, octave_idx_type& nc)
00111 {
00112   std::streampos pos = is.tellg ();
00113 
00114   int file_line_number = 0;
00115 
00116   nr = 0;
00117   nc = 0;
00118 
00119   while (is && ! error_state)
00120     {
00121       octave_quit ();
00122 
00123       std::string buf = get_mat_data_input_line (is);
00124 
00125       file_line_number++;
00126 
00127       size_t beg = buf.find_first_not_of (", \t");
00128 
00129       // If we see a CR as the last character in the buffer, we had a
00130       // CRLF pair as the line separator.  Any other CR in the text
00131       // will not be considered as whitespace.
00132 
00133       if (beg != std::string::npos && buf[beg] == '\r' && beg == buf.length () - 1)
00134         {
00135           // We had a blank line ending with a CRLF.  Handle it the
00136           // same as an empty line.
00137           beg = std::string::npos;
00138         }
00139 
00140       octave_idx_type tmp_nc = 0;
00141 
00142       while (beg != std::string::npos)
00143         {
00144           tmp_nc++;
00145 
00146           size_t end = buf.find_first_of (", \t", beg);
00147 
00148           if (end != std::string::npos)
00149             {
00150               beg = buf.find_first_not_of (", \t", end);
00151 
00152               if (beg == std::string::npos || (buf[beg] == '\r' &&
00153                                   beg == buf.length () - 1))
00154                 {
00155                   // We had a line with trailing spaces and
00156                   // ending with a CRLF, so this should look like EOL,
00157                   // not a new colum.
00158                   break;
00159                 }
00160             }
00161           else
00162             break;
00163         }
00164 
00165       if (tmp_nc > 0)
00166         {
00167           if (nc == 0)
00168             {
00169               nc = tmp_nc;
00170               nr++;
00171             }
00172           else if (nc == tmp_nc)
00173             nr++;
00174           else
00175             error ("load: %s: inconsistent number of columns near line %d",
00176                    filename.c_str (), file_line_number);
00177         }
00178     }
00179 
00180   if (nr == 0 || nc == 0)
00181     error ("load: file '%s' seems to be empty!", filename.c_str ());
00182 
00183   is.clear ();
00184   is.seekg (pos);
00185 }
00186 
00187 // Extract a matrix from a file of numbers only.
00188 //
00189 // Comments are not allowed.  The file should only have numeric values.
00190 //
00191 // Reads the file twice.  Once to find the number of rows and columns,
00192 // and once to extract the matrix.
00193 //
00194 // FILENAME is used for error messages.
00195 //
00196 // This format provides no way to tag the data as global.
00197 
00198 std::string
00199 read_mat_ascii_data (std::istream& is, const std::string& filename,
00200                      octave_value& tc)
00201 {
00202   std::string retval;
00203 
00204   std::string varname;
00205 
00206   size_t pos = filename.rfind ('/');
00207 
00208   if (pos != std::string::npos)
00209     varname = filename.substr (pos+1);
00210   else
00211     varname = filename;
00212 
00213   pos = varname.rfind ('.');
00214 
00215   if (pos != std::string::npos)
00216     varname = varname.substr (0, pos);
00217 
00218   size_t len = varname.length ();
00219   for (size_t i = 0; i < len; i++)
00220     {
00221       char c = varname[i];
00222       if (! (isalnum (c) || c == '_'))
00223         varname[i] = '_';
00224     }
00225 
00226   if (is_keyword (varname) || ! isalpha (varname[0]))
00227     varname.insert (0, "X");
00228 
00229   if (valid_identifier (varname))
00230     {
00231       octave_idx_type nr = 0;
00232       octave_idx_type nc = 0;
00233 
00234       int total_count = 0;
00235 
00236       get_lines_and_columns (is, filename, nr, nc);
00237 
00238       octave_quit ();
00239 
00240       if (! error_state && nr > 0 && nc > 0)
00241         {
00242           Matrix tmp (nr, nc);
00243 
00244           if (nr < 1 || nc < 1)
00245             is.clear (std::ios::badbit);
00246           else
00247             {
00248               double d;
00249               for (octave_idx_type i = 0; i < nr; i++)
00250                 {
00251                   std::string buf = get_mat_data_input_line (is);
00252 
00253                   std::istringstream tmp_stream (buf);
00254 
00255                   for (octave_idx_type j = 0; j < nc; j++)
00256                     {
00257                       octave_quit ();
00258 
00259                       d = octave_read_value<double> (tmp_stream);
00260 
00261                       if (tmp_stream || tmp_stream.eof ())
00262                         {
00263                           tmp.elem (i, j) = d;
00264                           total_count++;
00265 
00266                           // Skip whitespace and commas.
00267                           char c;
00268                           while (1)
00269                             {
00270                               tmp_stream >> c;
00271 
00272                               if (! tmp_stream)
00273                                 break;
00274 
00275                               if (! (c == ' ' || c == '\t' || c == ','))
00276                                 {
00277                                   tmp_stream.putback (c);
00278                                   break;
00279                                 }
00280                             }
00281 
00282                           if (tmp_stream.eof ())
00283                             break;
00284                         }
00285                       else
00286                         {
00287                           error ("load: failed to read matrix from file '%s'",
00288                                  filename.c_str ());
00289 
00290                           return retval;
00291                         }
00292 
00293                     }
00294                 }
00295             }
00296 
00297           if (is || is.eof ())
00298             {
00299               // FIXME -- not sure this is best, but it works.
00300 
00301               if (is.eof ())
00302                 is.clear ();
00303 
00304               octave_idx_type expected = nr * nc;
00305 
00306               if (expected == total_count)
00307                 {
00308                   tc = tmp;
00309                   retval = varname;
00310                 }
00311               else
00312                 error ("load: expected %d elements, found %d",
00313                        expected, total_count);
00314             }
00315           else
00316             error ("load: failed to read matrix from file '%s'",
00317                    filename.c_str ());
00318         }
00319       else
00320         error ("load: unable to extract matrix size from file '%s'",
00321                filename.c_str ());
00322     }
00323   else
00324     error ("load: unable to convert filename '%s' to valid identifier",
00325            filename.c_str ());
00326 
00327   return retval;
00328 }
00329 
00330 bool
00331 save_mat_ascii_data (std::ostream& os, const octave_value& val,
00332                      int precision, bool tabs)
00333 {
00334   bool success = true;
00335 
00336   if (val.is_complex_type ())
00337     warning ("save: omitting imaginary part for ASCII file");
00338 
00339   Matrix m = val.matrix_value (true);
00340 
00341   if (error_state)
00342     {
00343       success = false;
00344 
00345       error_state = 0;
00346     }
00347   else
00348     {
00349       long old_precision = os.precision ();
00350 
00351       os.precision (precision);
00352 
00353       std::ios::fmtflags oflags
00354         = os.flags (static_cast<std::ios::fmtflags> (std::ios::scientific));
00355 
00356       if (tabs)
00357         {
00358           for (octave_idx_type i = 0; i < m.rows (); i++)
00359             {
00360               for (octave_idx_type j = 0; j < m.cols (); j++)
00361                 {
00362                   // Omit leading tabs.
00363                   if (j != 0) os << '\t';
00364                   octave_write_double (os, m (i, j));
00365                 }
00366               os << "\n";
00367             }
00368         }
00369       else
00370         os << m;
00371 
00372       os.flags (oflags);
00373 
00374       os.precision (old_precision);
00375     }
00376 
00377   return (os && success);
00378 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines