]> git.ipfire.org Git - thirdparty/gcc.git/blame - c++tools/resolver.cc
Update copyright years.
[thirdparty/gcc.git] / c++tools / resolver.cc
CommitLineData
35fc243f 1/* C++ modules. Experimental! -*- c++ -*-
7adcbafe 2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
35fc243f
NS
3 Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22
23#include "resolver.h"
24// C++
25#include <algorithm>
c9bf4d43 26#include <memory>
35fc243f
NS
27// C
28#include <cstring>
29// OS
30#include <fcntl.h>
31#include <unistd.h>
09616422
NS
32#if 0 // 1 for testing no mmap
33#define MAPPED_READING 0
34#else
35#ifdef IN_GCC
36#if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0
37#define MAPPED_READING 1
38#else
39#define MAPPED_READING 0
40#endif
41#else
42#ifdef HAVE_SYS_MMAN_H
35fc243f 43#include <sys/mman.h>
09616422
NS
44#define MAPPED_READING 1
45#else
46#define MAPPED_READING 0
47#endif
48#endif
49#endif
50
35fc243f
NS
51#include <sys/types.h>
52#include <sys/stat.h>
53
09616422
NS
54#if !defined (IN_GCC) && !MAPPED_READING
55#define xmalloc(X) malloc(X)
56#endif
57
58#if !HOST_HAS_O_CLOEXEC
59#define O_CLOEXEC 0
60#endif
61
35fc243f
NS
62#ifndef DIR_SEPARATOR
63#define DIR_SEPARATOR '/'
64#endif
65
66module_resolver::module_resolver (bool map, bool xlate)
67 : default_map (map), default_translate (xlate)
68{
69}
70
71module_resolver::~module_resolver ()
72{
73 if (fd_repo >= 0)
74 close (fd_repo);
75}
76
77bool
78module_resolver::set_repo (std::string &&r, bool force)
79{
80 if (force || repo.empty ())
81 {
82 repo = std::move (r);
83 force = true;
84 }
85 return force;
86}
87
88bool
89module_resolver::add_mapping (std::string &&module, std::string &&file,
90 bool force)
91{
92 auto res = map.emplace (std::move (module), std::move (file));
93 if (res.second)
94 force = true;
95 else if (force)
96 res.first->second = std::move (file);
97
98 return force;
99}
100
101int
102module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
103{
104 struct stat stat;
105 if (fstat (fd, &stat) < 0)
106 return -errno;
107
108 if (!stat.st_size)
109 return 0;
110
09616422
NS
111 void *buffer = nullptr;
112#if MAPPED_READING
35fc243f
NS
113 // Just map the file, we're gonna read all of it, so no need for
114 // line buffering
09616422 115 buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
35fc243f
NS
116 if (buffer == MAP_FAILED)
117 return -errno;
c9bf4d43
JW
118 struct Deleter {
119 void operator()(void* p) const { munmap(p, size); }
120 size_t size;
121 };
122 std::unique_ptr<void, Deleter> guard(buffer, Deleter{(size_t)stat.st_size});
09616422
NS
123#else
124 buffer = xmalloc (stat.st_size);
125 if (!buffer)
126 return -errno;
c9bf4d43
JW
127 struct Deleter { void operator()(void* p) const { free(p); } };
128 std::unique_ptr<void, Deleter> guard(buffer);
09616422
NS
129 if (read (fd, buffer, stat.st_size) != stat.st_size)
130 return -errno;
131#endif
35fc243f
NS
132
133 size_t prefix_len = prefix ? strlen (prefix) : 0;
134 unsigned lineno = 0;
135
136 for (char const *begin = reinterpret_cast <char const *> (buffer),
137 *end = begin + stat.st_size, *eol;
138 begin != end; begin = eol + 1)
139 {
140 lineno++;
141 eol = std::find (begin, end, '\n');
142 if (eol == end)
143 // last line has no \n, ignore the line, you lose
144 break;
145
146 auto *pos = begin;
147 bool pfx_search = prefix_len != 0;
148
149 pfx_search:
150 while (*pos == ' ' || *pos == '\t')
151 pos++;
152
153 auto *space = pos;
154 while (*space != '\n' && *space != ' ' && *space != '\t')
155 space++;
156
157 if (pos == space)
158 // at end of line, nothing here
159 continue;
160
161 if (pfx_search)
162 {
163 if (size_t (space - pos) == prefix_len
164 && std::equal (pos, space, prefix))
165 pfx_search = false;
166 pos = space;
167 goto pfx_search;
168 }
169
170 std::string module (pos, space);
171 while (*space == ' ' || *space == '\t')
172 space++;
173 std::string file (space, eol);
174
175 if (module[0] == '$')
176 {
177 if (module == "$root")
178 set_repo (std::move (file));
179 else
180 return lineno;
181 }
182 else
183 {
184 if (file.empty ())
185 file = GetCMIName (module);
186 add_mapping (std::move (module), std::move (file), force);
187 }
188 }
189
35fc243f
NS
190 return 0;
191}
192
193char const *
194module_resolver::GetCMISuffix ()
195{
196 return "gcm";
197}
198
199module_resolver *
200module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
201 std::string &a, std::string &i)
202{
203 if (!version || version > Cody::Version)
204 s->ErrorResponse ("version mismatch");
205 else if (a != "GCC")
206 // Refuse anything but GCC
207 ErrorResponse (s, std::string ("only GCC supported"));
208 else if (!ident.empty () && ident != i)
209 // Failed ident check
210 ErrorResponse (s, std::string ("bad ident"));
211 else
212 // Success!
213 s->ConnectResponse ("gcc");
214
215 return this;
216}
217
218int
219module_resolver::ModuleRepoRequest (Cody::Server *s)
220{
221 s->PathnameResponse (repo);
222 return 0;
223}
224
225int
226module_resolver::cmi_response (Cody::Server *s, std::string &module)
227{
228 auto iter = map.find (module);
229 if (iter == map.end ())
230 {
62881833 231 std::string file = default_map ? GetCMIName (module) : std::string ();
35fc243f
NS
232 auto res = map.emplace (module, file);
233 iter = res.first;
234 }
235
236 if (iter->second.empty ())
237 s->ErrorResponse ("no such module");
238 else
239 s->PathnameResponse (iter->second);
240
241 return 0;
242}
243
244int
245module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
246 std::string &module)
247{
248 return cmi_response (s, module);
249}
250
251int
252module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
253 std::string &module)
254{
255 return cmi_response (s, module);
256}
257
258int
259module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
260 std::string &include)
261{
262 auto iter = map.find (include);
263 if (iter == map.end () && default_translate)
264 {
265 // Not found, look for it
266 auto file = GetCMIName (include);
267 struct stat statbuf;
268 bool ok = true;
269
270#if HAVE_FSTATAT
271 int fd_dir = AT_FDCWD;
272 if (!repo.empty ())
273 {
274 if (fd_repo == -1)
275 {
276 fd_repo = open (repo.c_str (),
277 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
278 if (fd_repo < 0)
279 fd_repo = -2;
280 }
281 fd_dir = fd_repo;
282 }
283
284 if (!repo.empty () && fd_repo < 0)
285 ok = false;
286 else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
287 || !S_ISREG (statbuf.st_mode))
288 ok = false;
289#else
290 auto append = repo;
291 append.push_back (DIR_SEPARATOR);
292 append.append (file);
293 if (stat (append.c_str (), &statbuf) < 0
294 || !S_ISREG (statbuf.st_mode))
295 ok = false;
296#endif
297 if (!ok)
298 // Mark as not present
299 file.clear ();
300 auto res = map.emplace (include, file);
301 iter = res.first;
302 }
303
304 if (iter == map.end () || iter->second.empty ())
305 s->BoolResponse (false);
306 else
307 s->PathnameResponse (iter->second);
308
309 return 0;
310}
311
c89d8053
IS
312/* This handles a client notification to the server that a CMI has been
313 produced for a module. For this simplified server, we just accept
314 the transaction and respond with "OK". */
315
316int
317module_resolver::ModuleCompiledRequest (Cody::Server *s, Cody::Flags,
318 std::string &)
319{
320 s->OKResponse();
321 return 0;
322}