ARTS 2.5.11 (git: 725533f0)
file.cc
Go to the documentation of this file.
1
2// File description
4
14// External declarations
16
17#include "arts.h"
18
19#include <algorithm>
20#include <cstdlib>
21#include <filesystem>
22#include <stdexcept>
23
24#include "array.h"
25#include "file.h"
26#include "parameters.h"
27
29// Default file names
31
43void filename_ascii(String& filename, const String& varname) {
44 if ("" == filename) {
45 extern const String out_basename;
46 filename = out_basename + "." + varname + ".aa";
47 }
48}
49
51// Functions to open and read ASCII files
53
63void open_output_file(ofstream& file, const std::string_view name) {
64 String ename = add_basedir(name);
65
66 try {
67 // Tell the stream that it should throw exceptions.
68 // Badbit means that the entire stream is corrupted, failbit means
69 // that the last operation has failed, but the stream is still
70 // valid. We don't want either to happen!
71 // FIXME: This does not yet work in egcs-2.91.66, try again later.
72 file.exceptions(ios::badbit | ios::failbit);
73
74 file.open(ename.c_str());
75
76 // See if the file is ok.
77 // FIXME: This should not be necessary anymore in the future, when
78 // g++ stream exceptions work properly. (In that case we would not
79 // get here if there really was a problem, because of the exception
80 // thrown by open().)
81 } catch (const std::exception& e) {
83 "Cannot open output file: ",
84 ename,
85 "\nMaybe you don't have write access to the directory or the file?");
86 }
87}
88
95void cleanup_output_file(ofstream& file, const std::string_view name) {
96 if (file.is_open()) {
97 streampos fpos = file.tellp();
98 file.close();
99 if (!fpos) std::filesystem::remove(expand_path(name).c_str());
100 }
101}
102
111void open_input_file(ifstream& file, const std::string_view name) {
112 String ename{expand_path(name)};
113
114 // Command line parameters which give us the include search path.
115 extern const Parameters parameters;
117 allpaths.insert(
118 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
119
120 ArrayOfString matching_files;
121 find_file(matching_files, ename, allpaths);
122
123 if (matching_files.nelem()) ename = matching_files[0];
124
125 // Tell the stream that it should throw exceptions.
126 // Badbit means that the entire stream is corrupted.
127 // On the other hand, end of file will not lead to an exception, you
128 // have to check this manually!
129 file.exceptions(ios::badbit);
130
131 // c_str explicitly converts to c String.
132 file.open(ename.c_str());
133
134 // See if the file is ok.
135 // FIXME: This should not be necessary anymore in the future, when
136 // g++ stream exceptions work properly.
137 ARTS_USER_ERROR_IF(!file,
138 "Cannot open input file: ",
139 ename,
140 "\nMaybe the file does not exist?");
141}
142
153 ArrayOfString text;
154 String linebuffer;
155
156 // Read as long as `is' is good.
157 // Contary to what I understood from the book, the explicit check
158 // for eof is necessary here, otherwise the last line is read twice
159 // if it is not terminated by a newline character!
160 while (is && is.good() && !is.eof()) {
161 // Read line from file into linebuffer:
162 getline(is, linebuffer);
163
164 // Append to end of text:
165 text.push_back(linebuffer);
166 }
167
168 // Check for error:
169 // FIXME: This should not be necessary anymore when stream
170 // exceptions work properly.
171 ARTS_USER_ERROR_IF(!is.eof(), "Read Error. Last line read:\n", linebuffer);
172
173 return text;
174}
175
186ArrayOfString read_text_from_file(const std::string_view name) {
187 ArrayOfString text{};
188 ifstream ifs;
189
190 // Open input stream:
191 open_input_file(ifs, name);
192 // No need to check for error, because open_input_file throws a
193 // runtime_error with an appropriate error message.
194
195 // Read the text from the stream. Here we catch the exception,
196 // because then we can issue a nicer error message that includes the
197 // filename.
198 try {
199 text = read_text_from_stream(ifs);
200 } catch (const std::runtime_error& x) {
201 ARTS_USER_ERROR("Error reading file: ", name, "\n", x.what());
202 }
203
204 return text;
205}
206
215void replace_all(String& s, const std::string_view what, const std::string_view with) {
216 Index j = s.find(what);
217 while (j != s.npos) {
218 s.replace(j, 1, with);
219 j = s.find(what, j + with.size());
220 }
221}
222
233int check_newline(const std::string_view s) {
234 String d = s;
235 int result = 0;
236
237 // Remove all whitespaces except \n
238 replace_all(d, " ", "");
239 replace_all(d, "\t", "");
240 replace_all(d, "\r", "");
241
242 const char* cp = d.c_str();
243 while (*cp == '\n') cp++;
244
245 if (!(*cp)) result = 1;
246
247 if (!result && d[d.length() - 1] != '\n')
248 result = 2;
249 else if (!result && d.length() > 2 && d[d.length() - 1] == '\n' &&
250 d[d.length() - 2] == '\n')
251 result = 3;
252
253 return result;
254}
255
265bool file_exists(const std::string_view filename) {
266 return std::filesystem::exists(filename) &&
267 !std::filesystem::is_directory(filename);
268}
269
285 const std::string_view filename,
286 const ArrayOfString& paths,
287 const ArrayOfString& extensions) {
288 bool exists = false;
289 std::string efilename{expand_path(filename)};
290
291 // filename contains full path
292 if (!paths.nelem() || std::filesystem::path(efilename).is_absolute()) {
293 for (const auto& ext : extensions) {
294 const String fullpath{efilename + ext};
295
296 if (file_exists(fullpath)) {
297 if (std::find(matches.begin(), matches.end(), fullpath) ==
298 matches.end())
299 matches.push_back(fullpath);
300 exists = true;
301 }
302 }
303 }
304 // filename contains no or relative path
305 else {
306 for (const auto& path : paths) {
307 for (const auto& ext : extensions) {
308 const String fullpath{expand_path(path) + "/" + efilename + ext};
309
310 if (file_exists(fullpath)) {
311 if (std::find(matches.begin(), matches.end(), fullpath) ==
312 matches.end())
313 matches.push_back(fullpath);
314 exists = true;
315 }
316 }
317 }
318 }
319
320 return exists;
321}
322
338void find_xml_file(String& filename, const Verbosity& verbosity) {
339 // Command line parameters which give us the include search path.
340 extern const Parameters parameters;
342 allpaths.insert(
343 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
344
345 ArrayOfString matching_files;
346 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
347
348 ARTS_USER_ERROR_IF(!matching_files.nelem(),
349 "Cannot find input file: ",
350 filename,
351 "\nSearch path: ",
352 allpaths);
353
354 if (matching_files.nelem() > 1) {
356 out1
357 << " WARNING: More than one file matching this name exists in the data path.\n"
358 << " Using the first file (1) found:\n";
359 for (Index i = 0; i < matching_files.nelem(); i++)
360 out1 << " (" << i + 1 << ") " << matching_files[i] << "\n";
361 }
362
363 filename = matching_files[0];
364}
365
378 // Command line parameters which give us the include search path.
379 extern const Parameters parameters;
381 allpaths.insert(
382 allpaths.end(), parameters.datapath.begin(), parameters.datapath.end());
383
384 ArrayOfString matching_files;
385 find_file(matching_files, filename, allpaths, {"", ".xml", ".gz", ".xml.gz"});
386
387 if (matching_files.nelem()) {
388 filename = matching_files[0];
389 return true;
390 }
391
392 return false;
393}
394
406 if ((path.length() == 1 && path[0] == '~') ||
407 (path.length() > 1 && path[0] == '~' && path[1] == '/')) {
408 path = String(std::getenv("HOME")) + String(path, 1);
409 }
410
411 return path;
412}
413
424String add_basedir(const std::string_view path) {
425 extern const Parameters parameters;
426 String expanded_path{expand_path(path)};
427
428 if (parameters.outdir.nelem() && path.length() && path[0] != '/') {
429 expanded_path = parameters.outdir + '/' + expanded_path;
430 }
431
432 return expanded_path;
433}
434
436
444String get_dirname(const std::string_view path) {
445 String dirname{};
446 if (!path.length()) return dirname;
447
448 ArrayOfString fileparts;
449 String{path}.split(fileparts, "/");
450 if (path[0] == '/') dirname = "/";
451 if (fileparts.nelem() > 1) {
452 for (Index i = 0; i < fileparts.nelem() - 1; i++) {
453 dirname += fileparts[i];
454 if (i < fileparts.nelem() - 2) dirname += "/";
455 }
456 }
457
458 return dirname;
459}
460
462
470ArrayOfString list_directory(const std::string_view dirname) {
471 ARTS_USER_ERROR_IF(!std::filesystem::is_directory(dirname),
472 "Error accessing directory: ",
473 dirname)
474
475 ArrayOfString files{};
476 for (const auto& filename :
477 std::filesystem::directory_iterator{dirname}) {
478 files.push_back(filename.path().string());
479 }
480
481 return files;
482}
483
496String make_filename_unique(const std::string_view filename, const String& extension) {
497 String basename = filename;
498 String extensionname;
499
500 // Split filename into base and extension
501 if (extension.length()) {
502 size_t pos = filename.rfind(extension);
503 if (pos == filename.length() - extension.length()) {
504 basename = filename.substr(0, filename.length() - extension.length());
505 extensionname = extension;
506 }
507 }
508
509 Index filenumber = 0;
510 ostringstream newfilename;
511 newfilename << basename << extensionname;
512
513 while (file_exists(newfilename.str()) ||
514 file_exists(newfilename.str() + ".gz")) {
515 filenumber++;
516 newfilename.str("");
517 newfilename << basename << "." << filenumber << extensionname;
518 }
519
520 return newfilename.str();
521}
This file contains the definition of Array.
The global header file for ARTS.
Index nelem() const ARTS_NOEXCEPT
Definition array.h:75
Structure to hold all command line Parameters.
Definition parameters.h:25
ArrayOfString includepath
List of paths to search for include files.
Definition parameters.h:89
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:70
ArrayOfString datapath
List of paths to search for data files.
Definition parameters.h:91
Index nelem() const
Definition mystring.h:172
void split(Array< my_basic_string< charT > > &aos, const my_basic_string< charT > &delim) const
Definition mystring.h:112
static const Index npos
Define npos:
Definition mystring.h:192
#define ARTS_USER_ERROR(...)
Definition debug.h:153
#define ARTS_USER_ERROR_IF(condition,...)
Definition debug.h:137
ArrayOfString read_text_from_stream(istream &is)
Read an ASCII stream and append the contents to the String array text.
Definition file.cc:152
ArrayOfString list_directory(const std::string_view dirname)
Return list of files in directory.
Definition file.cc:470
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:186
String add_basedir(const std::string_view path)
Definition file.cc:424
void find_xml_file(String &filename, const Verbosity &verbosity)
Find an xml file.
Definition file.cc:338
bool find_xml_file_existence(String &filename)
As find_xml_file but does not throw in the main body.
Definition file.cc:377
String expand_path(String path)
Definition file.cc:405
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:215
void filename_ascii(String &filename, const String &varname)
Gives the default file name for the ASCII formats.
Definition file.cc:43
void open_input_file(ifstream &file, const std::string_view name)
Open a file for reading.
Definition file.cc:111
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:233
String make_filename_unique(const std::string_view filename, const String &extension)
Make filename unique.
Definition file.cc:496
bool file_exists(const std::string_view filename)
Checks if the given file exists.
Definition file.cc:265
void open_output_file(ofstream &file, const std::string_view name)
Open a file for writing.
Definition file.cc:63
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:284
String get_dirname(const std::string_view path)
Return the parent directory of a path.
Definition file.cc:444
void cleanup_output_file(ofstream &file, const std::string_view name)
Closes the file.
Definition file.cc:95
This file contains basic functions to handle ASCII files.
String out_basename
The basename for the report file and for all other output files.
Definition messages.cc:25
#define CREATE_OUT1
Definition messages.h:187
my_basic_string< char > String
The String type for ARTS.
Definition mystring.h:199
Parameters parameters
Holds the command line parameters.
Definition parameters.cc:24
This file contains header information for the dealing with command line parameters.
#define d