summaryrefslogtreecommitdiff
path: root/tiger-compiler/lib/misc/file-library.cc
blob: fe344d0e76ceca2b457f1bbb71ce52b59f69cdea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
 ** \file misc/file-library.cc
 ** \brief Implements misc::file_library.
 */

#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>

#include <misc/contract.hh>
#include <misc/file-library.hh>

namespace misc
{
  void file_library::push_cwd()
  {
    // Store the working directory
    char cwd[MAXPATHLEN + 1];

    if (nullptr == getcwd(cwd, MAXPATHLEN + 1))
      throw std::runtime_error("working directory name too long");

    push_current_directory(path(std::string(cwd)));
  }

  file_library::file_library() { push_cwd(); }

  file_library::file_library(path p)
  {
    push_cwd();
    // Then only process given path.
    search_path_.emplace_back(p);
  }

  void file_library::append_dir_list(std::string path_list)
  {
    std::string::size_type pos;

    while ((pos = path_list.find(':')) != std::string::npos)
      {
        append_dir(path_list.substr(0, pos));
        path_list.erase(0, pos + 1);
      }
    append_dir(path_list);
  }

  path file_library::ensure_absolute_path(path p) const
  {
    if (p.is_absolute())
      return p;
    else
      return current_directory_get() / p;
  }

  void file_library::append_dir(path p)
  {
    search_path_.emplace_back(ensure_absolute_path(p));
  }

  void file_library::prepend_dir(path p)
  {
    search_path_.insert(search_path_.begin(), ensure_absolute_path(p));
  }

  void file_library::push_current_directory(path p)
  {
    // Ensure that path is absolute.
    if (!p.is_absolute())
      p = current_directory_get() / p;

    current_directory_.insert(current_directory_.begin(), p);
  }

  void file_library::pop_current_directory()
  {
    precondition(!current_directory_.empty());

    current_directory_.erase(current_directory_.begin());
  }

  path file_library::current_directory_get() const
  {
    precondition(!current_directory_.empty());

    return current_directory_.front();
  }

  path file_library::find_file(const std::string& file)
  {
    // Split file in two components, basename and basedir.
    path p = path(file);
    path directory = p.filename();

    if (directory.is_absolute())
      {
        // If file is absolute, just check that it exists.
        if (!std::filesystem::exists(path(file)))
          return path();
      }
    else
      {
        // Does the file can be found in current directory?
        if (find_in_directory(current_directory_get(), file))
          return (current_directory_get() / file).parent_path();

        directory = find_in_search_path(directory, p.filename().string());
      }

    return directory;
  }

  bool file_library::find_in_directory(const path& dir,
                                       const std::string& file) const
  {
    return std::filesystem::exists(path(dir / file));
  }

  path file_library::find_in_search_path(const path& relative_path,
                                         const std::string& filename) const
  {
    path checked_dir;

    // Otherwise start scanning the search path.
    for (const path& p : search_path_)
      {
        if (p.is_absolute())
          checked_dir = p;
        else
          checked_dir = current_directory_get() / p;

        checked_dir /= relative_path;

        if (find_in_directory(checked_dir, filename))
          return checked_dir;
      }

    // File not found in search path.
    return path();
  }

  std::ostream& file_library::dump(std::ostream& ostr) const
  {
    ostr << ".";
    for (const path& p : search_path_)
      ostr << ":" << p;
    return ostr;
  }

} // namespace misc