xref: /titanic_50/usr/src/lib/libast/common/path/pathfind.c (revision 275c9da86e89f8abf71135cf63d9fc23671b2e60)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 
37 typedef 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 
43 static 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 
53 int
54 pathinclude(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 
84 char*
85 pathfind(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(buf, tmp, "", PATH_REGULAR))
140 			return buf;
141 		if (type)
142 		{
143 			sfsprintf(tmp, sizeof(tmp), "%s/%s.%s", dp->dir, name, type);
144 			if (pathpath(buf, tmp, "", PATH_REGULAR))
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(buf, tmp, "", PATH_REGULAR))
159 			return buf;
160 		if (type)
161 		{
162 			sfsprintf(tmp, sizeof(tmp), "lib/%s/%s.%s", lib, name, type);
163 			if (pathpath(buf, tmp, "", PATH_REGULAR))
164 				return buf;
165 		}
166 	}
167 	return 0;
168 }
169