1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#pragma prototyped
23/*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * include style search support
28 */
29
30#include <ast.h>
31#include <error.h>
32#include <ls.h>
33
34#define directory(p,s)	(stat((p),(s))>=0&&S_ISDIR((s)->st_mode))
35#define regular(p,s)	(stat((p),(s))>=0&&(S_ISREG((s)->st_mode)||streq(p,"/dev/null")))
36
37typedef struct Dir_s			/* directory list element	*/
38{
39	struct Dir_s*	next;		/* next in list			*/
40	char		dir[1];		/* directory path		*/
41} Dir_t;
42
43static struct				/* directory list state		*/
44{
45	Dir_t*		head;		/* directory list head		*/
46	Dir_t*		tail;		/* directory list tail		*/
47} state;
48
49/*
50 * append dir to pathfind() include list
51 */
52
53int
54pathinclude(const char* dir)
55{
56	register Dir_t*	dp;
57	struct stat	st;
58
59	if (dir && *dir && !streq(dir, ".") && directory(dir, &st))
60	{
61		for (dp = state.head; dp; dp = dp->next)
62			if (streq(dir, dp->dir))
63				return 0;
64		if (!(dp = oldof(0, Dir_t, 1, strlen(dir))))
65			return -1;
66		strcpy(dp->dir, dir);
67		dp->next = 0;
68		if (state.tail)
69			state.tail = state.tail->next = dp;
70		else
71			state.head = state.tail = dp;
72	}
73	return 0;
74}
75
76/*
77 * return path to name using pathinclude() list
78 * path placed in <buf,size>
79 * if lib!=0 then pathpath() attempted after include search
80 * if type!=0 and name has no '.' then file.type also attempted
81 * any *: prefix in lib is ignored (discipline library dictionary support)
82 */
83
84char*
85pathfind(const char* name, const char* lib, const char* type, char* buf, size_t size)
86{
87	register Dir_t*		dp;
88	register char*		s;
89	char			tmp[PATH_MAX];
90	struct stat		st;
91
92	if (((s = strrchr(name, '/')) || (s = (char*)name)) && strchr(s, '.'))
93		type = 0;
94
95	/*
96	 * always check the unadorned path first
97	 * this handles . and absolute paths
98	 */
99
100	if (regular(name, &st))
101	{
102		strncopy(buf, name, size);
103		return buf;
104	}
105	if (type)
106	{
107		sfsprintf(buf, size, "%s.%s", name, type);
108		if (regular(buf, &st))
109			return buf;
110	}
111	if (*name == '/')
112		return 0;
113
114	/*
115	 * check the directory of the including file
116	 * on the assumption that error_info.file is properly stacked
117	 */
118
119	if (error_info.file && (s = strrchr(error_info.file, '/')))
120	{
121		sfsprintf(buf, size, "%-.*s%s", s - error_info.file + 1, error_info.file, name);
122		if (regular(buf, &st))
123			return buf;
124		if (type)
125		{
126			sfsprintf(buf, size, "%-.*s%s%.s", s - error_info.file + 1, error_info.file, name, type);
127			if (regular(buf, &st))
128				return buf;
129		}
130	}
131
132	/*
133	 * check the include dir list
134	 */
135
136	for (dp = state.head; dp; dp = dp->next)
137	{
138		sfsprintf(tmp, sizeof(tmp), "%s/%s", dp->dir, name);
139		if (pathpath(tmp, "", PATH_REGULAR, buf, size))
140			return buf;
141		if (type)
142		{
143			sfsprintf(tmp, sizeof(tmp), "%s/%s.%s", dp->dir, name, type);
144			if (pathpath(tmp, "", PATH_REGULAR, buf, size))
145				return buf;
146		}
147	}
148
149	/*
150	 * finally a lib related search on PATH
151	 */
152
153	if (lib)
154	{
155		if (s = strrchr((char*)lib, ':'))
156			lib = (const char*)s + 1;
157		sfsprintf(tmp, sizeof(tmp), "lib/%s/%s", lib, name);
158		if (pathpath(tmp, "", PATH_REGULAR, buf, size))
159			return buf;
160		if (type)
161		{
162			sfsprintf(tmp, sizeof(tmp), "lib/%s/%s.%s", lib, name, type);
163			if (pathpath(tmp, "", PATH_REGULAR, buf, size))
164				return buf;
165		}
166	}
167	return 0;
168}
169