4 * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the
5 * COPYRIGHT file at the base of the distribution.
11 static ipnodelist_t ImportPathList = RUNE_HEAD_INITIALIZER(ImportPathList);
13 static void DelImportPath(IPNode *ip);
14 static const char *temporaryImportPath(Stmt *st);
17 * Open the (possibly shared) parser associated with the ImportStmt,
18 * assigning and returning the parser. The first token of the file is
19 * retrieved and returned, or an appropriate TOK_ERR_* is returned.
21 * XXX locate an already-existant shared parser structure and use directly
24 ParseOpen(Stmt *st, Parse **pp, void **pdll)
26 Parse *p = zalloc(sizeof(Parse));
27 IPNode last_sip; /* backup relative path */
32 * Insert the current path at the head so relative imports always work.
34 dassert_stmt(st, st->st_Op == ST_Import);
35 p->p_IPath.ip_Flags |= IPF_STATIC;
36 p->p_IPath.ip_Path = safe_strdup(temporaryImportPath(st->st_Parent));
37 p->p_Format = PFMT_SOURCE;
38 RUNE_INSERT_HEAD(&ImportPathList, &p->p_IPath, ip_Node);
41 * last_sip iterates parent directories for convenience so the programmer
42 * doesn't have to use '..' all over the place.
44 bzero(&last_sip, sizeof(last_sip));
45 last_sip.ip_Flags |= IPF_STATIC;
48 * Scan import paths looking for the import
50 sip = RUNE_FIRST(&ImportPathList);
59 * Once we exhaust the list try iterating up "..".
61 * NOTE: Do not 'optimize' ".." by removing tail path elements, this
62 * will break softlinks.
66 if (strcmp(p->p_IPath.ip_Path, "./") == 0)
67 asprintf(&sip->ip_Path, "../");
69 asprintf(&sip->ip_Path, "%s../",
71 } else if (sip == &last_sip) {
75 stat(sip->ip_Path, &st1);
76 asprintf(&npath, "%s../", sip->ip_Path);
79 stat(sip->ip_Path, &st2);
82 * Detect the system root (it is ok to cross mount boundaries).
84 if (st1.st_ino == st2.st_ino &&
85 st1.st_dev == st2.st_dev) {
89 if (sip == &last_sip && sip->ip_Path == NULL)
93 * Construct a candidate path. If the path is a directory, tack on a
94 * "/main.d". If the path is relative, do it relative to the current
95 * source file's location. If the path is absolute, ignore sip.
97 if (st->st_ImportStmt.es_Path[0] == '/')
98 safe_asprintf(&npath, "%s%s",
99 st->st_ImportStmt.es_Path,
100 st->st_ImportStmt.es_File);
101 else if (sip->ip_Flags & (IPF_STATIC | IPF_ABSOLUTE))
102 safe_asprintf(&npath, "%s%s%s",
104 st->st_ImportStmt.es_Path,
105 st->st_ImportStmt.es_File);
107 safe_asprintf(&npath, "%s%s%s%s",
110 st->st_ImportStmt.es_Path,
111 st->st_ImportStmt.es_File);
114 * Locate the file, adjust for directories
116 r = stat(npath, &p->p_St);
117 if (r == 0 && S_ISDIR(p->p_St.st_mode)) {
119 safe_asprintf(&npath, "%s/main.d", npath);
120 r = stat(npath, &p->p_St);
124 * Figure out the extension. XXX convert the fatal error into a
127 if (pathdir == NULL) {
128 const char *ext = strrchr(npath, '.');
130 if (ext && strlen(ext) <= 3) {
132 if (strcmp(ext, "d") == 0)
134 else if (strcmp(ext, "r") == 0)
136 else if (strcmp(ext, "so") == 0)
138 else if (strcmp(ext, "a") == 0)
141 dfatal("Unknown import extension on %s\n", npath);
146 * SHARED RUNE SOURCE MODULE
148 * If we have already imported this and it is shared, set STF_SHARED
149 * and set es_Decl and st_MyGroup and do not open the file.
151 if ((mode == 'd' || mode == 'r') &&
153 (sg2 = GetSharedImport(&p->p_St)) != NULL
156 st->st_Flags |= STF_SHARED;
157 st->st_ImportStmt.es_SemGroup = sg2;
159 safe_replacef(&st->st_ImportStmt.es_Path,
161 safe_replace(&st->st_ImportStmt.es_File,
165 safe_replace(&p->p_IPath.ip_Path,
166 st->st_ImportStmt.es_Path);
167 dassert_stmt(st, sg2->sg_Stmt->st_Op == ST_Module);
169 *pdll = sg2->sg_Stmt->st_ImportStmt.es_DLL;
175 * RUNE SOURCE MODULE TO PARSE
177 * Attempt to open the path. If we succeed we have to do some fixups
178 * for the directory case.
182 (p->p_Lex = LexOpen(npath, &p->p_Token)) != NULL) {
184 * note that st_ImportStmt.es_SemGroup is not yet known. The
185 * ParseModule() code will deal with it.
187 st->st_ImportStmt.es_Parser = p;
191 safe_replacef(&st->st_ImportStmt.es_Path,
193 safe_replace(&st->st_ImportStmt.es_File,
197 safe_replace(&p->p_IPath.ip_Path,
198 st->st_ImportStmt.es_Path);
200 * Inherit the declaration block of the caller and prime the
203 p->p_CurSemGroup = st->st_MyGroup;
204 t = LexToken(&p->p_Token);
209 * DYNAMIC LINK LIBRARY
211 * This is typically used to add system and library calls to the
214 if (mode == 'r' && r == 0) {
215 void *dll = dlopen(npath, RTLD_NOW | RTLD_LOCAL);
218 void (*init) (void)= dlsym(dll, "init");
223 st->st_ImportStmt.es_SemGroup = NULL;
226 st->st_Flags |= STF_SHARED;
229 * XXX should really make the group NULL here, but then the
230 * GetSharedImport check will not work. XXX
232 SetSharedImport(&p->p_St, st->st_MyGroup);
235 &st->st_ImportStmt.es_Path,
238 &st->st_ImportStmt.es_File,
244 st->st_ImportStmt.es_Path);
251 "UNABLE TO LOAD DLL: %s %s\n",
258 st->st_ImportStmt.es_Parser = NULL;
259 t = TOK_ERR_IMPORT_NOT_FOUND;
262 * If the import statement is using an absolute path itself, we
263 * ignore 'sip' and so there is no need to loop.
265 if (st->st_ImportStmt.es_Path[0] == '/')
267 if (sip != &last_sip)
268 sip = RUNE_NEXT(sip, ip_Node);
270 if (last_sip.ip_Path) {
271 free(last_sip.ip_Path);
272 last_sip.ip_Path = NULL; /* safety */
275 DelImportPath(&p->p_IPath);
284 * XXX what to do here?
294 ParseClose(Parse **pp)
298 if ((p = *pp) != NULL) {
301 /* XXX free stuff up */
302 zfree_wipe(p, sizeof(Parse));
307 AddImportPath(const char *path, int flags)
309 IPNode *ip = zalloc(sizeof(IPNode));
311 safe_asprintf(&ip->ip_Path, "%s/", path);
312 RUNE_INSERT_TAIL(&ImportPathList, ip, ip_Node);
313 ip->ip_Flags |= flags;
315 ip->ip_Flags |= IPF_ABSOLUTE;
319 DelImportPath(IPNode *ip)
322 safe_free(&ip->ip_Path);
323 RUNE_REMOVE(&ImportPathList, ip, ip_Node);
325 if ((ip->ip_Flags & IPF_STATIC) == 0)
326 zfree(ip, sizeof(IPNode));
330 PrefixImportPaths(const char *basePath)
334 RUNE_FOREACH(ip, &ImportPathList, ip_Node) {
335 if (ip->ip_Flags & IPF_BASEPATH) {
336 safe_replacef(&ip->ip_Path, "%s%s",
337 basePath, ip->ip_Path);
339 if (basePath[0] == '/')
340 ip->ip_Flags |= IPF_ABSOLUTE;
345 temporaryImportPath(Stmt *st)
348 if (st->st_Op == ST_Import)
349 return (st->st_ImportStmt.es_Path);
357 typedef RUNE_HEAD(ipslist, ImportShare) ipslist_t;
359 typedef struct ImportShare {
360 RUNE_ENTRY(ImportShare) is_Node;
363 SemGroup *is_SemGroup;
366 static ipslist_t ISList = RUNE_HEAD_INITIALIZER(ISList);
369 SetSharedImport(struct stat *st, SemGroup *sg)
371 ImportShare *is = zalloc(sizeof(ImportShare));
373 RUNE_INSERT_TAIL(&ISList, is, is_Node);
374 is->is_RDev = st->st_rdev;
375 is->is_Ino = st->st_ino;
376 is->is_SemGroup = sg;
380 GetSharedImport(struct stat *st)
384 RUNE_FOREACH(is, &ISList, is_Node) {
385 if (st->st_ino == is->is_Ino && st->st_rdev == is->is_RDev)
386 return (is->is_SemGroup);