ARTS 2.5.9 (git: 825fa5f2)
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 <cstdlib>
38#include <filesystem>
39#include <stdexcept>
40
41#include "array.h"
42#include "file.h"
43#include "parameters.h"
44
46// Default file names
48
60void filename_ascii(String& filename, const String& varname) {
61 if ("" == filename) {
62 extern const String out_basename;
63 filename = out_basename + "." + varname + ".aa";
64 }
65}
66
68// Functions to open and read ASCII files
70
80void open_output_file(ofstream& file, const std::string_view name) {
81 String ename = add_basedir(name);
82
83 try {
84 // Tell the stream that it should throw exceptions.
85 // Badbit means that the entire stream is corrupted, failbit means
86 // that the last operation has failed, but the stream is still
87 // valid. We don't want either to happen!
88 // FIXME: This does not yet work in egcs-2.91.66, try again later.
89 file.exceptions(ios::badbit | ios::failbit);
90
91 file.open(ename.c_str());
92
93 // See if the file is ok.
94 // FIXME: This should not be necessary anymore in the future, when
95 // g++ stream exceptions work properly. (In that case we would not
96 // get here if there really was a problem, because of the exception
97 // thrown by open().)
98 } catch (const std::exception& e) {
100 "Cannot open output file: ",
101 ename,
102 "\nMaybe you don't have write access to the directory or the file?");
103 }
104}
105
112void cleanup_output_file(ofstream& file, const std::string_view name) {
113 if (file.is_open()) {
114 streampos fpos = file.tellp();
115 file.close();
116 if (!fpos) std::filesystem::remove(expand_path(name).c_str());
117 }
118}
119
128void open_input_file(ifstream& file, const std::string_view name) {
129 String ename{expand_path(name)};
130
131 // Command line parameters which give us the include search path.
132 extern const Parameters parameters;
134 allpaths.insert(
135 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
136
137 ArrayOfString matching_files;
138 find_file(matching_files, ename, allpaths);
139
140 if (matching_files.nelem()) ename = matching_files[0];
141
142 // Tell the stream that it should throw exceptions.
143 // Badbit means that the entire stream is corrupted.
144 // On the other hand, end of file will not lead to an exception, you
145 // have to check this manually!
146 file.exceptions(ios::badbit);
147
148 // c_str explicitly converts to c String.
149 file.open(ename.c_str());
150
151 // See if the file is ok.
152 // FIXME: This should not be necessary anymore in the future, when
153 // g++ stream exceptions work properly.
154 ARTS_USER_ERROR_IF(!file,
155 "Cannot open input file: ",
156 ename,
157 "\nMaybe the file does not exist?");
158}
159
170 ArrayOfString text;
171 String linebuffer;
172
173 // Read as long as `is' is good.
174 // Contary to what I understood from the book, the explicit check
175 // for eof is necessary here, otherwise the last line is read twice
176 // if it is not terminated by a newline character!
177 while (is && is.good() && !is.eof()) {
178 // Read line from file into linebuffer:
179 getline(is, linebuffer);
180
181 // Append to end of text:
182 text.push_back(linebuffer);
183 }
184
185 // Check for error:
186 // FIXME: This should not be necessary anymore when stream
187 // exceptions work properly.
188 ARTS_USER_ERROR_IF(!is.eof(), "Read Error. Last line read:\n", linebuffer);
189
190 return text;
191}
192
203ArrayOfString read_text_from_file(const std::string_view name) {
204 ArrayOfString text{};
205 ifstream ifs;
206
207 // Open input stream:
208 open_input_file(ifs, name);
209 // No need to check for error, because open_input_file throws a
210 // runtime_error with an appropriate error message.
211
212 // Read the text from the stream. Here we catch the exception,
213 // because then we can issue a nicer error message that includes the
214 // filename.
215 try {
216 text = read_text_from_stream(ifs);
217 } catch (const std::runtime_error& x) {
218 ARTS_USER_ERROR("Error reading file: ", name, "\n", x.what());
219 }
220
221 return text;
222}
223
232void replace_all(String& s, const std::string_view what, const std::string_view with) {
233 Index j = s.find(what);
234 while (j != s.npos) {
235 s.replace(j, 1, with);
236 j = s.find(what, j + with.size());
237 }
238}
239
250int check_newline(const std::string_view s) {
251 String d = s;
252 int result = 0;
253
254 // Remove all whitespaces except \n
255 replace_all(d, " ", "");
256 replace_all(d, "\t", "");
257 replace_all(d, "\r", "");
258
259 const char* cp = d.c_str();
260 while (*cp == '\n') cp++;
261
262 if (!(*cp)) result = 1;
263
264 if (!result && d[d.length() - 1] != '\n')
265 result = 2;
266 else if (!result && d.length() > 2 && d[d.length() - 1] == '\n' &&
267 d[d.length() - 2] == '\n')
268 result = 3;
269
270 return result;
271}
272
282bool file_exists(const std::string_view filename) {
283 return std::filesystem::exists(filename) &&
284 !std::filesystem::is_directory(filename);
285}
286
302 const std::string_view filename,
303 const ArrayOfString& paths,
304 const ArrayOfString& extensions) {
305 bool exists = false;
306 std::string efilename{expand_path(filename)};
307
308 // filename contains full path
309 if (!paths.nelem() || std::filesystem::path(efilename).is_absolute()) {
310 for (const auto& ext : extensions) {
311 const String fullpath{efilename + ext};
312
313 if (file_exists(fullpath)) {
314 if (std::find(matches.begin(), matches.end(), fullpath) ==
315 matches.end())
316 matches.push_back(fullpath);
317 exists = true;
318 }
319 }
320 }
321 // filename contains no or relative path
322 else {
323 for (const auto& path : paths) {
324 for (const auto& ext : extensions) {
325 const String fullpath{expand_path(path) + "/" + efilename + ext};
326
327 if (file_exists(fullpath)) {
328 if (std::find(matches.begin(), matches.end(), fullpath) ==
329 matches.end())
330 matches.push_back(fullpath);
331 exists = true;
332 }
333 }
334 }
335 }
336
337 return exists;
338}
339
355void find_xml_file(String& filename, const Verbosity& verbosity) {
356 // Command line parameters which give us the include search path.
357 extern const Parameters parameters;
359 allpaths.insert(
360 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
361
362 ArrayOfString matching_files;
363 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
364
365 ARTS_USER_ERROR_IF(!matching_files.nelem(),
366 "Cannot find input file: ",
367 filename,
368 "\nSearch path: ",
369 allpaths);
370
371 if (matching_files.nelem() > 1) {
373 out1
374 << " WARNING: More than one file matching this name exists in the data path.\n"
375 << " Using the first file (1) found:\n";
376 for (Index i = 0; i < matching_files.nelem(); i++)
377 out1 << " (" << i + 1 << ") " << matching_files[i] << "\n";
378 }
379
380 filename = matching_files[0];
381}
382
395 // Command line parameters which give us the include search path.
396 extern const Parameters parameters;
398 allpaths.insert(
399 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
400
401 ArrayOfString matching_files;
402 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
403
404 if (matching_files.nelem()) {
405 filename = matching_files[0];
406 return true;
407 }
408
409 return false;
410}
411
423 if ((path.length() == 1 && path[0] == '~') ||
424 (path.length() > 1 && path[0] == '~' && path[1] == '/')) {
425 path = String(std::getenv("HOME")) + String(path, 1);
426 }
427
428 return path;
429}
430
441String add_basedir(const std::string_view path) {
442 extern const Parameters parameters;
443 String expanded_path{expand_path(path)};
444
445 if (parameters.outdir.nelem() && path.length() && path[0] != '/') {
446 expanded_path = parameters.outdir + '/' + expanded_path;
447 }
448
449 return expanded_path;
450}
451
453
461String get_dirname(const std::string_view path) {
462 String dirname{};
463 if (!path.length()) return dirname;
464
465 ArrayOfString fileparts;
466 String{path}.split(fileparts, "/");
467 if (path[0] == '/') dirname = "/";
468 if (fileparts.nelem() > 1) {
469 for (Index i = 0; i < fileparts.nelem() - 1; i++) {
470 dirname += fileparts[i];
471 if (i < fileparts.nelem() - 2) dirname += "/";
472 }
473 }
474
475 return dirname;
476}
477
479
487ArrayOfString list_directory(const std::string_view dirname) {
488 ARTS_USER_ERROR_IF(!std::filesystem::is_directory(dirname),
489 "Error accessing directory: ",
490 dirname)
491
492 ArrayOfString files{};
493 for (const auto& filename :
494 std::filesystem::directory_iterator{dirname}) {
495 files.push_back(filename.path().string());
496 }
497
498 return files;
499}
500
513String make_filename_unique(const std::string_view filename, const String& extension) {
514 String basename = filename;
515 String extensionname;
516
517 // Split filename into base and extension
518 if (extension.length()) {
519 size_t pos = filename.rfind(extension);
520 if (pos == filename.length() - extension.length()) {
521 basename = filename.substr(0, filename.length() - extension.length());
522 extensionname = extension;
523 }
524 }
525
526 Index filenumber = 0;
527 ostringstream newfilename;
528 newfilename << basename << extensionname;
529
530 while (file_exists(newfilename.str()) ||
531 file_exists(newfilename.str() + ".gz")) {
532 filenumber++;
533 newfilename.str("");
534 newfilename << basename << "." << filenumber << extensionname;
535 }
536
537 return newfilename.str();
538}
This file contains the definition of Array.
The global header file for ARTS.
Index nelem() const ARTS_NOEXCEPT
Definition: array.h:92
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
Definition: mystring.h:189
void split(Array< my_basic_string< charT > > &aos, const my_basic_string< charT > &delim) const
Definition: mystring.h:129
static const Index npos
Define npos:
Definition: mystring.h:209
#define ARTS_USER_ERROR(...)
Definition: debug.h:150
#define ARTS_USER_ERROR_IF(condition,...)
Definition: debug.h:134
ArrayOfString read_text_from_stream(istream &is)
Read an ASCII stream and append the contents to the String array text.
Definition: file.cc:169
ArrayOfString list_directory(const std::string_view dirname)
Return list of files in directory.
Definition: file.cc:487
ArrayOfString read_text_from_file(const std::string_view name)
Reads an ASCII file and appends the contents to the String vector text.
Definition: file.cc:203
String add_basedir(const std::string_view path)
Definition: file.cc:441
void find_xml_file(String &filename, const Verbosity &verbosity)
Find an xml file.
Definition: file.cc:355
bool find_xml_file_existence(String &filename)
As find_xml_file but does not throw in the main body.
Definition: file.cc:394
String expand_path(String path)
Definition: file.cc:422
void replace_all(String &s, const std::string_view what, const std::string_view with)
Replace all occurances of ‘what’ in ‘s’ with ‘with’.
Definition: file.cc:232
void filename_ascii(String &filename, const String &varname)
Gives the default file name for the ASCII formats.
Definition: file.cc:60
void open_input_file(ifstream &file, const std::string_view name)
Open a file for reading.
Definition: file.cc:128
int check_newline(const std::string_view s)
Checks if there is exactly one newline character at the end of the string.
Definition: file.cc:250
String make_filename_unique(const std::string_view filename, const String &extension)
Make filename unique.
Definition: file.cc:513
bool file_exists(const std::string_view filename)
Checks if the given file exists.
Definition: file.cc:282
void open_output_file(ofstream &file, const std::string_view name)
Open a file for writing.
Definition: file.cc:80
bool find_file(ArrayOfString &matches, const std::string_view filename, const ArrayOfString &paths, const ArrayOfString &extensions)
Searches through paths for a file with a matching name.
Definition: file.cc:301
String get_dirname(const std::string_view path)
Return the parent directory of a path.
Definition: file.cc:461
void cleanup_output_file(ofstream &file, const std::string_view name)
Closes the file.
Definition: file.cc:112
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
String out_basename
The basename for the report file and for all other output files.
Definition: messages.cc:42
#define CREATE_OUT1
Definition: messages.h:204
my_basic_string< char > String
The String type for ARTS.
Definition: mystring.h:216
Parameters parameters
Holds the command line parameters.
Definition: parameters.cc:41
This file contains header information for the dealing with command line parameters.
#define d