std::stringstream error;
Provenance provenance{GetProvenance(start)};
AllSources *allSources{cooked_->allSources()};
+ const SourceFile *currentFile{allSources->GetSourceFile(provenance)};
+ if (currentFile != nullptr) {
+ allSources->PushSearchPathDirectory(DirectoryName(currentFile->path()));
+ }
const SourceFile *included{allSources->Open(path, &error)};
+ if (currentFile != nullptr) {
+ allSources->PopSearchPathDirectory();
+ }
if (included == nullptr) {
messages_->Put({provenance, error.str()});
anyFatalErrors_ = true;
return origin[at - origin.start];
}
+void AllSources::PushSearchPathDirectory(std::string directory) {
+ // gfortran and ifort append to current path, PGI prepends
+ searchPath_.push_back(directory);
+}
+
+std::string AllSources::PopSearchPathDirectory() {
+ std::string directory{searchPath_.back()};
+ searchPath_.pop_back();
+ return directory;
+}
+
const SourceFile *AllSources::Open(std::string path, std::stringstream *error) {
std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>()};
- if (source->Open(path, error)) {
+ if (source->Open(LocateSourceFile(path, searchPath_), error)) {
return ownedSourceFiles_.emplace_back(std::move(source)).get();
}
return nullptr;
size_t size() const { return bytes_; }
const char &operator[](Provenance) const;
+ void PushSearchPathDirectory(std::string);
+ std::string PopSearchPathDirectory();
const SourceFile *Open(std::string path, std::stringstream *error);
ProvenanceRange AddIncludedFile(const SourceFile &, ProvenanceRange);
size_t bytes_{0};
std::map<char, Provenance> compilerInsertionProvenance_;
std::vector<std::unique_ptr<SourceFile>> ownedSourceFiles_;
+ std::vector<std::string> searchPath_;
};
class CookedSource {
#include <cerrno>
#include <cstring>
#include <fcntl.h>
+#include <iostream> // TODO pmk rm
#include <memory>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <vector>
// TODO: Port to Windows &c.
return result;
}
+std::string DirectoryName(std::string path) {
+ auto lastSlash = path.rfind("/");
+ return lastSlash == std::string::npos ? path : path.substr(0, lastSlash);
+}
+
+std::string LocateSourceFile(
+ std::string name, const std::vector<std::string> &searchPath) {
+ if (name.empty() || name == "-" || name[0] == '/') {
+ return name;
+ }
+ for (const std::string &dir : searchPath) {
+ std::string path{dir + '/' + name};
+ struct stat statbuf;
+ if (stat(path.c_str(), &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) {
+ return path;
+ }
+ }
+ return name;
+}
+
bool SourceFile::Open(std::string path, std::stringstream *error) {
Close();
path_ = path;
error_path = "'"s + path + "'";
fileDescriptor_ = open(path.c_str(), O_RDONLY);
if (fileDescriptor_ < 0) {
- *error << "could not open '" << error_path
- << "': " << std::strerror(errno);
+ *error << "could not open " << error_path << ": " << std::strerror(errno);
return false;
}
}
namespace Fortran {
namespace parser {
+std::string DirectoryName(std::string path);
+std::string LocateSourceFile(
+ std::string name, const std::vector<std::string> &searchPath);
+
class SourceFile {
public:
SourceFile() {}
~SourceFile();
- bool Open(std::string path, std::stringstream *error);
- void Close();
std::string path() const { return path_; }
const char *content() const { return content_; }
size_t bytes() const { return bytes_; }
size_t lines() const { return lineStart_.size(); }
+
+ bool Open(std::string path, std::stringstream *error);
+ void Close();
std::pair<int, int> FindOffsetLineAndColumn(size_t) const;
private:
bool enableOldDebugLines{false};
int columns{72};
+ Fortran::parser::AllSources allSources;
+
while (!args.empty()) {
if (args.front().empty()) {
args.pop_front();
dumpCookedChars = true;
} else if (flag == "-ed") {
enableOldDebugLines = true;
+ } else if (flag == "-I") {
+ allSources.PushSearchPathDirectory(args.front());
+ args.pop_front();
+ } else if (flag.substr(0, 2) == "-I") {
+ allSources.PushSearchPathDirectory(flag.substr(2, std::string::npos));
} else {
std::cerr << "unknown flag: '" << flag << "'\n";
return 1;
}
}
- Fortran::parser::AllSources allSources;
std::stringstream error;
const auto *sourceFile = allSources.Open(path, &error);
if (!sourceFile) {
state.set_strictConformance(standard);
state.set_columns(columns);
state.set_enableOldDebugLines(enableOldDebugLines);
- state.PushContext("source file '"s + path + "'");
Fortran::parser::UserState ustate;
state.set_userState(&ustate);