ARTS 2.5.0 (git: 9ee3ac6c)
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
19// File description
21
31// External declarations
33
34#include "arts.h"
35
36#include <algorithm>
37#include <cfloat>
38#include <cmath>
39#include <cstdio>
40#include <cstdlib>
41#include <limits>
42#include <stdexcept>
43
44// For getdir
45#include <dirent.h>
46#include <errno.h>
47#include <sys/stat.h>
48#include <sys/types.h>
49
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53
54#include "array.h"
55#include "file.h"
56#include "parameters.h"
57
59// Default file names
61
73void filename_ascii(String& filename, const String& varname) {
74 if ("" == filename) {
75 extern const String out_basename;
76 filename = out_basename + "." + varname + ".aa";
77 }
78}
79
81// Functions to open and read ASCII files
83
93void open_output_file(ofstream& file, const String& name) {
94 String ename = add_basedir(name);
95
96 try {
97 // Tell the stream that it should throw exceptions.
98 // Badbit means that the entire stream is corrupted, failbit means
99 // that the last operation has failed, but the stream is still
100 // valid. We don't want either to happen!
101 // FIXME: This does not yet work in egcs-2.91.66, try again later.
102 file.exceptions(ios::badbit | ios::failbit);
103
104 // c_str explicitly converts to c String.
105 file.open(ename.c_str());
106
107 // See if the file is ok.
108 // FIXME: This should not be necessary anymore in the future, when
109 // g++ stream exceptions work properly. (In that case we would not
110 // get here if there really was a problem, because of the exception
111 // thrown by open().)
112 } catch (const std::exception& e) {
113 ostringstream os;
114 os << "Cannot open output file: " << ename << '\n'
115 << "Maybe you don't have write access "
116 << "to the directory or the file?";
117 throw runtime_error(os.str());
118 }
119}
120
127#ifdef HAVE_REMOVE
128void cleanup_output_file(ofstream& file, const String& name) {
129 if (file.is_open()) {
130 streampos fpos = file.tellp();
131 file.close();
132 if (!fpos) unlink(expand_path(name).c_str());
133 }
134}
135#else
136void cleanup_output_file(ofstream&, const String&) {}
137#endif
138
147void open_input_file(ifstream& file, const String& name) {
148 String ename = expand_path(name);
149
150 // Command line parameters which give us the include search path.
151 extern const Parameters parameters;
153 allpaths.insert(
154 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
155
156 ArrayOfString matching_files;
157 find_file(matching_files, ename, allpaths);
158
159 if (matching_files.nelem()) ename = matching_files[0];
160
161 // Tell the stream that it should throw exceptions.
162 // Badbit means that the entire stream is corrupted.
163 // On the other hand, end of file will not lead to an exception, you
164 // have to check this manually!
165 file.exceptions(ios::badbit);
166
167 // c_str explicitly converts to c String.
168 file.open(ename.c_str());
169
170 // See if the file is ok.
171 // FIXME: This should not be necessary anymore in the future, when
172 // g++ stream exceptions work properly.
173 if (!file) {
174 ostringstream os;
175 os << "Cannot open input file: " << ename << '\n'
176 << "Maybe the file does not exist?";
177 throw runtime_error(os.str());
178 }
179}
180
190void read_text_from_stream(ArrayOfString& text, istream& is) {
191 String linebuffer;
192
193 // Read as long as `is' is good.
194 // Contary to what I understood from the book, the explicit check
195 // for eof is necessary here, otherwise the last line is read twice
196 // if it is not terminated by a newline character!
197 while (is && is.good() && !is.eof()) {
198 // Read line from file into linebuffer:
199 getline(is, linebuffer);
200
201 // Append to end of text:
202 text.push_back(linebuffer);
203 }
204
205 // Check for error:
206 // FIXME: This should not be necessary anymore when stream
207 // exceptions work properly.
208 if (!is.eof()) {
209 ostringstream os;
210 os << "Read Error. Last line read:\n" << linebuffer;
211 throw runtime_error(os.str());
212 }
213}
214
225void read_text_from_file(ArrayOfString& text, const String& name) {
226 ifstream ifs;
227
228 // Open input stream:
229 open_input_file(ifs, name);
230 // No need to check for error, because open_input_file throws a
231 // runtime_error with an appropriate error message.
232
233 // Read the text from the stream. Here we catch the exception,
234 // because then we can issue a nicer error message that includes the
235 // filename.
236 try {
237 read_text_from_stream(text, ifs);
238 } catch (const std::runtime_error& x) {
239 ostringstream os;
240 os << "Error reading file: " << name << '\n' << x.what();
241 throw runtime_error(os.str());
242 }
243}
244
253void replace_all(String& s, const String& what, const String& with) {
254 Index j = s.find(what);
255 while (j != s.npos) {
256 s.replace(j, 1, with);
257 j = s.find(what, j + with.size());
258 }
259}
260
271int check_newline(const String& s) {
272 String d = s;
273 int result = 0;
274
275 // Remove all whitespaces except \n
276 replace_all(d, " ", "");
277 replace_all(d, "\t", "");
278 replace_all(d, "\r", "");
279
280 const char* cp = d.c_str();
281 while ((*cp == '\n') && *cp) cp++;
282
283 if (!(*cp)) result = 1;
284
285 if (!result && d[d.length() - 1] != '\n')
286 result = 2;
287 else if (!result && d.length() > 2 && d[d.length() - 1] == '\n' &&
288 d[d.length() - 2] == '\n')
289 result = 3;
290
291 return result;
292}
293
303bool file_exists(const String& filename) {
304 bool exists = false;
305
306 struct stat st;
307 if (lstat(filename.c_str(), &st) >= 0 && !S_ISDIR(st.st_mode)) {
308 fstream fin;
309 fin.open(filename.c_str(), ios::in);
310 if (fin.is_open()) {
311 exists = true;
312 }
313 fin.close();
314 }
315
316 return exists;
317}
318
329 char* fullrealpath;
330 fullrealpath = realpath(filename.c_str(), NULL);
331 if (fullrealpath) {
332 String retpath(fullrealpath);
333 free(fullrealpath);
334 return retpath;
335 } else
336 return filename;
337}
338
354 const String& filename,
355 const ArrayOfString& paths,
356 const ArrayOfString& extensions) {
357 bool exists = false;
358 String efilename = expand_path(filename);
359
360 // filename contains full path
361 if (!paths.nelem() || (efilename.nelem() && efilename[0] == '/')) {
362 for (ArrayOfString::const_iterator ext = extensions.begin();
363 ext != extensions.end();
364 ext++) {
365 String fullpath = get_absolute_path(efilename + *ext);
366 // Full path + extension
367 if (file_exists(fullpath)) {
368 if (std::find(matches.begin(), matches.end(), fullpath) ==
369 matches.end())
370 matches.push_back(fullpath);
371 exists = true;
372 }
373 }
374 }
375 // filename contains no or relative path
376 else {
377 for (ArrayOfString::const_iterator path = paths.begin();
378 path != paths.end();
379 path++) {
380 for (ArrayOfString::const_iterator ext = extensions.begin();
381 ext != extensions.end();
382 ext++) {
383 String fullpath =
384 get_absolute_path(expand_path(*path) + "/" + efilename + *ext);
385
386 if (file_exists(fullpath)) {
387 if (std::find(matches.begin(), matches.end(), fullpath) ==
388 matches.end())
389 matches.push_back(fullpath);
390 exists = true;
391 }
392 }
393 }
394 }
395
396 return exists;
397}
398
414void find_xml_file(String& filename, const Verbosity& verbosity) {
415 // Command line parameters which give us the include search path.
416 extern const Parameters parameters;
418 allpaths.insert(
419 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
420
421 ArrayOfString matching_files;
422 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
423
424 if (matching_files.nelem() > 1) {
426 out1
427 << " WARNING: More than one file matching this name exists in the data path.\n"
428 << " Using the first file (1) found:\n";
429 for (Index i = 0; i < matching_files.nelem(); i++)
430 out1 << " (" << i + 1 << ") " << matching_files[i] << "\n";
431 } else if (!matching_files.nelem()) {
432 ostringstream os;
433 os << "Cannot find input file: " << filename << endl;
434 os << "Search path: " << allpaths << endl;
435 throw runtime_error(os.str());
436 }
437
438 filename = matching_files[0];
439}
440
453 // Command line parameters which give us the include search path.
454 extern const Parameters parameters;
456 allpaths.insert(
457 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
458
459 ArrayOfString matching_files;
460 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
461
462 if (matching_files.nelem()) {
463 filename = matching_files[0];
464 return true;
465 } else {
466 return false;
467 }
468}
469
481 if ((path.nelem() == 1 && path[0] == '~') ||
482 (path.nelem() > 1 && path[0] == '~' && path[1] == '/')) {
483 return String(getenv("HOME")) + String(path, 1);
484 } else {
485 return path;
486 }
487}
488
500 extern const Parameters parameters;
501 String expanded_path = expand_path(path);
502
503 if (parameters.outdir.nelem() && path.nelem() && path[0] != '/') {
504 expanded_path = parameters.outdir + '/' + expanded_path;
505 }
506
507 return expanded_path;
508}
509
511
519void get_dirname(String& dirname, const String& path) {
520 dirname = "";
521 if (!path.nelem()) return;
522
523 ArrayOfString fileparts;
524 path.split(fileparts, "/");
525 if (path[0] == '/') dirname = "/";
526 if (fileparts.nelem() > 1) {
527 for (Index i = 0; i < fileparts.nelem() - 1; i++) {
528 dirname += fileparts[i];
529 if (i < fileparts.nelem() - 2) dirname += "/";
530 }
531 }
532}
533
535
543void list_directory(ArrayOfString& files, String dirname) {
544 DIR* dp;
545 struct dirent* dirp;
546 if ((dp = opendir(dirname.c_str())) == NULL) {
547 ostringstream os;
548 os << "Error(" << errno << ") opening " << dirname << endl;
549 throw runtime_error(os.str());
550 }
551
552 while ((dirp = readdir(dp)) != NULL) {
553 files.push_back(String(dirp->d_name));
554 }
555
556 closedir(dp);
557}
558
571void make_filename_unique(String& filename, const String& extension) {
572 String basename = filename;
573 String extensionname;
574
575 // Split filename into base and extension
576 if (extension.length()) {
577 size_t pos = filename.rfind(extension);
578 if (pos == filename.length() - extension.length()) {
579 basename = filename.substr(0, filename.length() - extension.length());
580 extensionname = extension;
581 }
582 }
583
584 Index filenumber = 0;
585 ostringstream newfilename;
586 newfilename << basename << extensionname;
587
588 while (file_exists(newfilename.str()) ||
589 file_exists(newfilename.str() + ".gz")) {
590 filenumber++;
591 newfilename.str("");
592 newfilename << basename << "." << filenumber << extensionname;
593 }
594
595 filename = newfilename.str();
596}
This file contains the definition of Array.
The global header file for ARTS.
String out_basename
The basename for the report file and for all other output files.
Definition: messages.cc:42
Parameters parameters
Holds the command line parameters.
Definition: parameters.cc:41
Index nelem() const ARTS_NOEXCEPT
Number of elements.
Definition: array.h:195
Structure to hold all command line Parameters.
Definition: parameters.h:42
ArrayOfString includepath
List of paths to search for include files.
Definition: parameters.h:106
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:87
ArrayOfString datapath
List of paths to search for data files.
Definition: parameters.h:108
Index nelem() const
Number of elements.
Definition: mystring.h:253
void split(Array< my_basic_string< charT > > &aos, const my_basic_string< charT > &delim) const
Split string into substrings.
Definition: mystring.h:213
static const Index npos
Define npos:
Definition: mystring.h:107
void make_filename_unique(String &filename, const String &extension)
Make filename unique.
Definition: file.cc:571
void replace_all(String &s, const String &what, const String &with)
Replace all occurances of ‘what’ in ‘s’ with ‘with’.
Definition: file.cc:253
void find_xml_file(String &filename, const Verbosity &verbosity)
Find an xml file.
Definition: file.cc:414
bool file_exists(const String &filename)
Checks if the given file exists.
Definition: file.cc:303
void cleanup_output_file(ofstream &, const String &)
Closes the file.
Definition: file.cc:136
String add_basedir(const String &path)
Definition: file.cc:499
void open_output_file(ofstream &file, const String &name)
Open a file for writing.
Definition: file.cc:93
bool find_xml_file_existence(String &filename)
As find_xml_file but does not throw in the main body.
Definition: file.cc:452
int check_newline(const String &s)
Checks if there is exactly one newline character at the end of the string.
Definition: file.cc:271
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:190
void get_dirname(String &dirname, const String &path)
Return the parent directory of a path.
Definition: file.cc:519
void filename_ascii(String &filename, const String &varname)
Gives the default file name for the ASCII formats.
Definition: file.cc:73
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:353
void list_directory(ArrayOfString &files, String dirname)
Return list of files in directory.
Definition: file.cc:543
void open_input_file(ifstream &file, const String &name)
Open a file for reading.
Definition: file.cc:147
String expand_path(const String &path)
Definition: file.cc:480
String get_absolute_path(const String &filename)
Convert relative path to absolute path.
Definition: file.cc:328
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:225
This file contains basic functions to handle ASCII files.
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
#define CREATE_OUT1
Definition: messages.h:205
my_basic_string< char > String
The String type for ARTS.
Definition: mystring.h:287
This file contains header information for the dealing with command line parameters.
#define d