ARTS  2.2.66
file.cc
Go to the documentation of this file.
1 /* Copyright (C) 2000-2012 Stefan Buehler <sbuehler@ltu.se>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA. */
17 
18 
20 // File description
22 
33 // External declarations
36 
37 #include "arts.h"
38 
39 #include <stdexcept>
40 #include <cmath>
41 #include <cfloat>
42 #include <cstdio>
43 #include <cstdlib>
44 #include <limits>
45 #include <algorithm>
46 
47 // For getdir
48 #include <sys/types.h>
49 #include <dirent.h>
50 #include <errno.h>
51 #include <sys/stat.h>
52 
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
56 
57 #include "matpackI.h"
58 #include "array.h"
59 #include "parameters.h"
60 #include "file.h"
61 
62 
64 // Default file names
66 
79  String& filename,
80  const String& varname )
81 {
82  if ( "" == filename )
83  {
84  extern const String out_basename;
85  filename = out_basename+"."+varname+".aa";
86  }
87 }
88 
89 
91 // Functions to open and read ASCII files
93 
103 void open_output_file(ofstream& file, const String& name)
104 {
105  String ename = add_basedir(name);
106 
107  try
108  {
109  // Tell the stream that it should throw exceptions.
110  // Badbit means that the entire stream is corrupted, failbit means
111  // that the last operation has failed, but the stream is still
112  // valid. We don't want either to happen!
113  // FIXME: This does not yet work in egcs-2.91.66, try again later.
114  file.exceptions(ios::badbit |
115  ios::failbit);
116 
117  // c_str explicitly converts to c String.
118  file.open(ename.c_str() );
119 
120  // See if the file is ok.
121  // FIXME: This should not be necessary anymore in the future, when
122  // g++ stream exceptions work properly. (In that case we would not
123  // get here if there really was a problem, because of the exception
124  // thrown by open().)
125  }
126  catch (exception e)
127  {
128  ostringstream os;
129  os << "Cannot open output file: " << ename << '\n'
130  << "Maybe you don't have write access "
131  << "to the directory or the file?";
132  throw runtime_error(os.str());
133  }
134 }
135 
136 
143 #ifdef HAVE_REMOVE
144 void cleanup_output_file(ofstream& file, const String& name)
145 {
146  if (file.is_open())
147  {
148  streampos fpos = file.tellp();
149  file.close();
150  if (!fpos) unlink(expand_path(name).c_str());
151  }
152 }
153 #else
154 void cleanup_output_file(ofstream&, const String&) {}
155 #endif
156 
157 
166 void open_input_file(ifstream& file, const String& name)
167 {
168  String ename = expand_path(name);
169 
170  // Command line parameters which give us the include search path.
171  extern const Parameters parameters;
173  allpaths.insert(allpaths.end(),
174  parameters.datapath.begin(),
175  parameters.datapath.end());
176 
177  ArrayOfString matching_files;
178  find_file(matching_files, ename, allpaths);
179 
180  if (matching_files.nelem()) ename = matching_files[0];
181 
182  // Tell the stream that it should throw exceptions.
183  // Badbit means that the entire stream is corrupted.
184  // On the other hand, end of file will not lead to an exception, you
185  // have to check this manually!
186  file.exceptions(ios::badbit);
187 
188  // c_str explicitly converts to c String.
189  file.open(ename.c_str() );
190 
191  // See if the file is ok.
192  // FIXME: This should not be necessary anymore in the future, when
193  // g++ stream exceptions work properly.
194  if (!file)
195  {
196  ostringstream os;
197  os << "Cannot open input file: " << ename << '\n'
198  << "Maybe the file does not exist?";
199  throw runtime_error(os.str());
200  }
201 }
202 
203 
213 void read_text_from_stream(ArrayOfString& text, istream& is)
214 {
215  String linebuffer;
216 
217  // Read as long as `is' is good.
218  // Contary to what I understood from the book, the explicit check
219  // for eof is necessary here, otherwise the last line is read twice
220  // if it is not terminated by a newline character!
221  while (is && is.good() && !is.eof())
222  {
223  // Read line from file into linebuffer:
224  getline(is,linebuffer);
225 
226  // Append to end of text:
227  text.push_back(linebuffer);
228  }
229 
230  // Check for error:
231  // FIXME: This should not be necessary anymore when stream
232  // exceptions work properly.
233  if ( !is.eof() ) {
234  ostringstream os;
235  os << "Read Error. Last line read:\n" << linebuffer;
236  throw runtime_error(os.str());
237  }
238 
239 }
240 
241 
252 void read_text_from_file(ArrayOfString& text, const String& name)
253 {
254  ifstream ifs;
255 
256  // Open input stream:
257  open_input_file(ifs, name);
258  // No need to check for error, because open_input_file throws a
259  // runtime_error with an appropriate error message.
260 
261  // Read the text from the stream. Here we catch the exception,
262  // because then we can issue a nicer error message that includes the
263  // filename.
264  try
265  {
266  read_text_from_stream(text,ifs);
267  }
268  catch (runtime_error x)
269  {
270  ostringstream os;
271  os << "Error reading file: " << name << '\n'
272  << x.what();
273  throw runtime_error(os.str());
274  }
275 }
276 
277 
286 void replace_all(String& s, const String& what, const String& with)
287 {
288  Index j = s.find(what);
289  while ( j != s.npos )
290  {
291  s.replace(j,1,with);
292  j = s.find(what,j+with.size());
293  }
294 }
295 
296 
307 int check_newline(const String& s)
308 {
309  String d = s;
310  int result = 0;
311 
312  // Remove all whitespaces except \n
313  replace_all (d, " ", "");
314  replace_all (d, "\t", "");
315  replace_all (d, "\r", "");
316 
317  const char *cp = d.c_str ();
318  while ((*cp == '\n') && *cp) cp++;
319 
320  if (!(*cp))
321  result = 1;
322 
323  if (!result && d[d.length () - 1] != '\n')
324  result = 2;
325  else if (!result && d.length () > 2
326  && d[d.length () - 1] == '\n' && d[d.length () - 2] == '\n')
327  result = 3;
328 
329  return result;
330 }
331 
332 
333 
343 bool file_exists(const String& filename)
344 {
345  bool exists = false;
346 
347  struct stat st;
348  if (lstat(filename.c_str(), &st) >= 0
349  && !S_ISDIR(st.st_mode))
350  {
351  fstream fin;
352  fin.open(filename.c_str(), ios::in);
353  if (fin.is_open())
354  {
355  exists=true;
356  }
357  fin.close();
358  }
359 
360  return exists;
361 }
362 
363 
374 {
375  char *fullrealpath;
376  fullrealpath = realpath(filename.c_str(), NULL);
377  if (fullrealpath)
378  {
379  String retpath(fullrealpath);
380  free(fullrealpath);
381  return retpath;
382  }
383  else
384  return filename;
385 }
386 
387 
402 bool find_file(ArrayOfString& matches, const String& filename, const ArrayOfString& paths,
403  const ArrayOfString& extensions)
404 {
405  bool exists = false;
406  String efilename = expand_path(filename);
407 
408  // filename contains full path
409  if (!paths.nelem()
410  || (efilename.nelem() && efilename[0] == '/'))
411  {
412  for (ArrayOfString::const_iterator ext = extensions.begin();
413  ext != extensions.end(); ext++)
414  {
415  String fullpath = get_absolute_path(efilename + *ext);
416  // Full path + extension
417  if (file_exists (fullpath))
418  {
419  if (std::find(matches.begin(), matches.end(), fullpath) == matches.end())
420  matches.push_back(fullpath);
421  exists = true;
422  }
423  }
424  }
425  // filename contains no or relative path
426  else
427  {
428  for (ArrayOfString::const_iterator path = paths.begin(); path != paths.end(); path++)
429  {
430  for (ArrayOfString::const_iterator ext = extensions.begin();
431  ext != extensions.end(); ext++)
432  {
433  String fullpath = get_absolute_path(expand_path(*path) + "/" + efilename + *ext);
434 
435  if (file_exists (fullpath))
436  {
437  if (std::find(matches.begin(), matches.end(), fullpath) == matches.end())
438  matches.push_back(fullpath);
439  exists = true;
440  }
441  }
442  }
443  }
444 
445  return exists;
446 }
447 
448 
464 void find_xml_file(String& filename, const Verbosity& verbosity)
465 {
466  // Command line parameters which give us the include search path.
467  extern const Parameters parameters;
469  allpaths.insert(allpaths.end(),
470  parameters.datapath.begin(),
471  parameters.datapath.end());
472 
473  ArrayOfString matching_files;
474  find_file(matching_files, filename, allpaths, MakeArray<String>("", ".xml", ".gz", ".xml.gz"));
475 
476  if (matching_files.nelem() > 1)
477  {
478  CREATE_OUT1;
479  out1 << " WARNING: More than one file matching this name exists in the data path.\n"
480  << " Using the first file (1) found:\n";
481  for (Index i = 0; i < matching_files.nelem(); i++)
482  out1 << " (" << i+1 << ") " << matching_files[i] << "\n";
483  }
484  else if (!matching_files.nelem())
485  {
486  ostringstream os;
487  os << "Cannot find input file: " << filename << endl;
488  os << "Search path: " << allpaths << endl;
489  throw runtime_error(os.str());
490  }
491 
492  filename = matching_files[0];
493 }
494 
495 
507 {
508  if ((path.nelem() == 1 && path[0] == '~')
509  || (path.nelem() > 1 && path[0] == '~' && path[1] == '/'))
510  {
511  return String(getenv ("HOME")) + String(path, 1);
512  }
513  else
514  {
515  return path;
516  }
517 }
518 
519 
531 {
532  extern const Parameters parameters;
533  String expanded_path = expand_path(path);
534 
535  if (parameters.outdir.nelem() && path.nelem() && path[0] != '/')
536  {
537  expanded_path = parameters.outdir + '/' + expanded_path;
538  }
539 
540  return expanded_path;
541 }
542 
543 
545 
553 void get_dirname(String& dirname, const String& path)
554 {
555  dirname = "";
556  if (!path.nelem()) return;
557 
558  ArrayOfString fileparts;
559  path.split(fileparts, "/");
560  if (path[0] == '/') dirname = "/";
561  if (fileparts.nelem() > 1)
562  {
563  for(Index i = 0; i < fileparts.nelem()-1; i++)
564  {
565  dirname += fileparts[i];
566  if (i < fileparts.nelem()-2) dirname += "/";
567  }
568  }
569 }
570 
571 
573 
581 void list_directory(ArrayOfString& files, String dirname)
582 {
583  DIR *dp;
584  struct dirent *dirp;
585  if((dp = opendir(dirname.c_str())) == NULL)
586  {
587  ostringstream os;
588  os << "Error(" << errno << ") opening " << dirname << endl;
589  throw runtime_error(os.str());
590  }
591 
592  while ((dirp = readdir(dp)) != NULL)
593  {
594  files.push_back(String(dirp->d_name));
595  }
596 
597  closedir(dp);
598 }
599 
612 void make_filename_unique(String& filename, const String& extension)
613 {
614  String basename = filename;
615  String extensionname;
616 
617  // Split filename into base and extension
618  if (extension.length())
619  {
620  size_t pos = filename.rfind(extension);
621  if (pos == filename.length() - extension.length())
622  {
623  basename = filename.substr(0, filename.length() - extension.length());
624  extensionname = extension;
625  }
626  }
627 
628  Index filenumber = 0;
629  ostringstream newfilename;
630  newfilename << basename << extensionname;
631 
632  while (file_exists(newfilename.str())
633  || file_exists(newfilename.str() + ".gz"))
634  {
635  filenumber++;
636  newfilename.str("");
637  newfilename << basename << "." << filenumber << extensionname;
638  }
639 
640  filename = newfilename.str();
641 }
642 
643 
645 // IO manipulation classes for parsing nan and inf
647 
649 double_istream::parse_on_fail (double& x, bool neg) {
650  const char *exp[] = { "", "inf", "Inf", "nan", "NaN" };
651  const char *e = exp[0];
652  int l = 0;
653  char inf[4];
654  char *c = inf;
655  if (neg) *c++ = '-';
656  in.clear();
657  if (!(in >> *c).good()) return *this;
658  switch (*c) {
659  case 'i': e = exp[l=1]; break;
660  case 'I': e = exp[l=2]; break;
661  case 'n': e = exp[l=3]; break;
662  case 'N': e = exp[l=4]; break;
663  }
664  while (*c == *e) {
665  if ((e-exp[l]) == 2) break;
666  ++e; if (!(in >> *++c).good()) break;
667  }
668  if (in.good() && *c == *e) {
669  switch (l) {
670  case 1:
671  case 2: x = std::numeric_limits<double>::infinity(); break;
672  case 3:
673  case 4: x = std::numeric_limits<double>::quiet_NaN(); break;
674  }
675  if (neg) x = -x;
676  return *this;
677  } else if (!in.good()) {
678  if (!in.fail()) return *this;
679  in.clear(); --c;
680  }
681  do { in.putback(*c); } while (c-- != inf);
682  in.setstate(std::ios_base::failbit);
683  return *this;
684 }
685 
686 
687 const double_imanip&
688 operator>>(std::istream& in, const double_imanip& dm) {
689  dm.in = &in;
690  return dm;
691 }
Parameters::outdir
String outdir
If this is specified (with the -o –outdir option), it is used as the base directory for the report fi...
Definition: parameters.h:86
Parameters
Structure to hold all command line Parameters.
Definition: parameters.h:42
cleanup_output_file
void cleanup_output_file(ofstream &, const String &)
Closes the file.
Definition: file.cc:154
open_input_file
void open_input_file(ifstream &file, const String &name)
Open a file for reading.
Definition: file.cc:166
get_dirname
void get_dirname(String &dirname, const String &path)
Return the parent directory of a path.
Definition: file.cc:553
array.h
This file contains the definition of Array.
CREATE_OUT1
#define CREATE_OUT1
Definition: messages.h:212
operator>>
const double_imanip & operator>>(std::istream &in, const double_imanip &dm)
Definition: file.cc:688
matpackI.h
Array
This can be used to make arrays out of anything.
Definition: array.h:107
read_text_from_stream
void read_text_from_stream(ArrayOfString &text, istream &is)
Read an ASCII stream and append the contents to the String array text.
Definition: file.cc:213
my_basic_string
The implementation for String, the ARTS string class.
Definition: mystring.h:64
get_absolute_path
String get_absolute_path(const String &filename)
Convert relative path to absolute path.
Definition: file.cc:373
double_imanip
Input manipulator class for doubles to enable nan and inf parsing.
Definition: file.h:124
find_xml_file
void find_xml_file(String &filename, const Verbosity &verbosity)
Find an xml file.
Definition: file.cc:464
Verbosity
Definition: messages.h:50
double_istream::in
std::istream & in
Definition: file.h:119
make_filename_unique
void make_filename_unique(String &filename, const String &extension)
Make filename unique.
Definition: file.cc:612
file_exists
bool file_exists(const String &filename)
Checks if the given file exists.
Definition: file.cc:343
parameters.h
This file contains header information for the dealing with command line parameters.
double_imanip::in
std::istream * in
Definition: file.h:138
out_basename
String out_basename
The basename for the report file and for all other output files.
Definition: messages.cc:42
open_output_file
void open_output_file(ofstream &file, const String &name)
Open a file for writing.
Definition: file.cc:103
my_basic_string::nelem
Index nelem() const
Number of elements.
Definition: mystring.h:278
list_directory
void list_directory(ArrayOfString &files, String dirname)
Return list of files in directory.
Definition: file.cc:581
my_basic_string::split
void split(Array< my_basic_string< charT > > &aos, const my_basic_string< charT > &delim) const
Split string into substrings.
Definition: mystring.h:233
read_text_from_file
void read_text_from_file(ArrayOfString &text, const String &name)
Reads an ASCII file and appends the contents to the String vector text.
Definition: file.cc:252
expand_path
String expand_path(const String &path)
Definition: file.cc:506
parameters
Parameters parameters
Holds the command line parameters.
Definition: parameters.cc:41
String
my_basic_string< char > String
The String type for ARTS.
Definition: mystring.h:318
check_newline
int check_newline(const String &s)
Checks if there is exactly one newline character at the end of the string.
Definition: file.cc:307
filename_ascii
void filename_ascii(String &filename, const String &varname)
Gives the default file name for the ASCII formats.
Definition: file.cc:78
double_istream
Input stream class for doubles that correctly handles nan and inf.
Definition: file.h:101
add_basedir
String add_basedir(const String &path)
Definition: file.cc:530
file.h
This file contains basic functions to handle ASCII files.
double_istream::parse_on_fail
double_istream & parse_on_fail(double &x, bool neg)
Definition: file.cc:649
MakeArray
Explicit construction of Arrays.
Definition: make_array.h:52
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:35
my_basic_string::npos
static const Index npos
Define npos:
Definition: mystring.h:105
Parameters::includepath
ArrayOfString includepath
List of paths to search for include files.
Definition: parameters.h:105
Parameters::datapath
ArrayOfString datapath
List of paths to search for data files.
Definition: parameters.h:107
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:176
arts.h
The global header file for ARTS.
find_file
bool find_file(ArrayOfString &matches, const String &filename, const ArrayOfString &paths, const ArrayOfString &extensions)
Searches through paths for a file with a matching name.
Definition: file.cc:402
replace_all
void replace_all(String &s, const String &what, const String &with)
Replace all occurances of ‘what’ in ‘s’ with ‘with’.
Definition: file.cc:286