1 /* C++ modules. Experimental! -*- c++ -*-
2 Copyright (C) 2017-2020 Free Software Foundation, Inc.
3 Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
5 This file is part of GCC.
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)
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.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
32 #include <sys/types.h>
36 #define DIR_SEPARATOR '/'
39 module_resolver::module_resolver (bool map, bool xlate)
40 : default_map (map), default_translate (xlate)
44 module_resolver::~module_resolver ()
51 module_resolver::set_repo (std::string &&r, bool force)
53 if (force || repo.empty ())
62 module_resolver::add_mapping (std::string &&module, std::string &&file,
65 auto res = map.emplace (std::move (module), std::move (file));
69 res.first->second = std::move (file);
75 module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
78 if (fstat (fd, &stat) < 0)
84 // Just map the file, we're gonna read all of it, so no need for
86 void *buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
87 if (buffer == MAP_FAILED)
90 size_t prefix_len = prefix ? strlen (prefix) : 0;
93 for (char const *begin = reinterpret_cast <char const *> (buffer),
94 *end = begin + stat.st_size, *eol;
95 begin != end; begin = eol + 1)
98 eol = std::find (begin, end, '\n');
100 // last line has no \n, ignore the line, you lose
104 bool pfx_search = prefix_len != 0;
107 while (*pos == ' ' || *pos == '\t')
111 while (*space != '\n' && *space != ' ' && *space != '\t')
115 // at end of line, nothing here
120 if (size_t (space - pos) == prefix_len
121 && std::equal (pos, space, prefix))
127 std::string module (pos, space);
128 while (*space == ' ' || *space == '\t')
130 std::string file (space, eol);
132 if (module[0] == '$')
134 if (module == "$root")
135 set_repo (std::move (file));
142 file = GetCMIName (module);
143 add_mapping (std::move (module), std::move (file), force);
147 munmap (buffer, stat.st_size);
153 module_resolver::GetCMISuffix ()
159 module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
160 std::string &a, std::string &i)
162 if (!version || version > Cody::Version)
163 s->ErrorResponse ("version mismatch");
165 // Refuse anything but GCC
166 ErrorResponse (s, std::string ("only GCC supported"));
167 else if (!ident.empty () && ident != i)
168 // Failed ident check
169 ErrorResponse (s, std::string ("bad ident"));
172 s->ConnectResponse ("gcc");
178 module_resolver::ModuleRepoRequest (Cody::Server *s)
180 s->PathnameResponse (repo);
185 module_resolver::cmi_response (Cody::Server *s, std::string &module)
187 auto iter = map.find (module);
188 if (iter == map.end ())
192 file = std::move (GetCMIName (module));
193 auto res = map.emplace (module, file);
197 if (iter->second.empty ())
198 s->ErrorResponse ("no such module");
200 s->PathnameResponse (iter->second);
206 module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
209 return cmi_response (s, module);
213 module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
216 return cmi_response (s, module);
220 module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
221 std::string &include)
223 auto iter = map.find (include);
224 if (iter == map.end () && default_translate)
226 // Not found, look for it
227 auto file = GetCMIName (include);
232 int fd_dir = AT_FDCWD;
237 fd_repo = open (repo.c_str (),
238 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
245 if (!repo.empty () && fd_repo < 0)
247 else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
248 || !S_ISREG (statbuf.st_mode))
252 append.push_back (DIR_SEPARATOR);
253 append.append (file);
254 if (stat (append.c_str (), &statbuf) < 0
255 || !S_ISREG (statbuf.st_mode))
259 // Mark as not present
261 auto res = map.emplace (include, file);
265 if (iter == map.end () || iter->second.empty ())
266 s->BoolResponse (false);
268 s->PathnameResponse (iter->second);