Commit | Line | Data |
---|---|---|
90b8dad5 | 1 | /* |
62a2aae7 KB |
2 | * Copyright (c) 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
90b8dad5 CT |
4 | * |
5 | * This software was developed by the Computer Systems Engineering group | |
6 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
7 | * contributed to Berkeley. | |
8 | * | |
9 | * All advertising materials mentioning features or use of this software | |
10 | * must display the following acknowledgement: | |
11 | * This product includes software developed by the University of | |
12 | * California, Lawrence Berkeley Laboratories. | |
13 | * | |
14 | * %sccs.include.redist.c% | |
15 | * | |
62a2aae7 | 16 | * @(#)files.c 8.1 (Berkeley) %G% |
90b8dad5 CT |
17 | */ |
18 | ||
19 | #include <sys/param.h> | |
20 | #include <errno.h> | |
21 | #include <stdio.h> | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include "config.h" | |
25 | ||
26 | extern const char *yyfile; | |
27 | ||
28 | /* | |
29 | * We check that each full path name is unique. File base names | |
30 | * should generally also be unique, e.g., having both a net/xx.c and | |
31 | * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably | |
32 | * wrong, but is permitted under some conditions. | |
33 | */ | |
34 | static struct hashtab *basetab; /* file base names */ | |
35 | static struct hashtab *pathtab; /* full path names */ | |
36 | ||
37 | static struct files **nextfile; | |
38 | static struct files **unchecked; | |
39 | ||
40 | void | |
41 | initfiles() | |
42 | { | |
43 | ||
44 | basetab = ht_new(); | |
45 | pathtab = ht_new(); | |
46 | nextfile = &allfiles; | |
47 | unchecked = &allfiles; | |
48 | } | |
49 | ||
50 | static void | |
51 | showprev(pref, fi) | |
52 | const char *pref; | |
53 | register struct files *fi; | |
54 | { | |
55 | ||
56 | xerror(fi->fi_srcfile, fi->fi_srcline, | |
57 | "%sfile %s ...", pref, fi->fi_path); | |
58 | errors--; | |
59 | } | |
60 | ||
61 | void | |
62 | addfile(path, opts, flags, rule) | |
63 | const char *path; | |
64 | struct nvlist *opts; | |
65 | int flags; | |
66 | const char *rule; | |
67 | { | |
68 | struct files *fi; | |
69 | const char *base, *dotp, *tail; | |
70 | size_t baselen; | |
71 | int needc, needf; | |
72 | char buf[200]; | |
73 | ||
74 | /* check various errors */ | |
75 | needc = flags & FI_NEEDSCOUNT; | |
76 | needf = flags & FI_NEEDSFLAG; | |
77 | if (needc && needf) { | |
78 | error("cannot mix needs-count and needs-flag"); | |
79 | goto bad; | |
80 | } | |
81 | if (opts == NULL && (needc || needf)) { | |
82 | error("nothing to %s for %s", needc ? "count" : "flag", path); | |
83 | goto bad; | |
84 | } | |
85 | if ((fi = ht_lookup(pathtab, path)) != NULL) { | |
86 | showprev("", fi); | |
87 | error("file %s listed again", path); | |
88 | goto bad; | |
89 | } | |
90 | ||
91 | /* find last part of pathname, and same without trailing suffix */ | |
92 | tail = rindex(path, '/'); | |
93 | if (tail == NULL) | |
94 | tail = path; | |
95 | else | |
96 | tail++; | |
97 | dotp = rindex(tail, '.'); | |
98 | if (dotp == NULL || dotp[1] == 0 || | |
99 | (baselen = dotp - tail) >= sizeof(buf)) { | |
100 | error("invalid pathname `%s'", path); | |
101 | goto bad; | |
102 | } | |
103 | ||
104 | /* | |
105 | * Make a copy of the path without the .c/.s/whatever suffix. | |
106 | * This must be unique per "files" file (e.g., a specific | |
107 | * file can override a standard file, but no standard file | |
108 | * can override another standard file). This is not perfect | |
109 | * but should catch any major errors. | |
110 | */ | |
111 | bcopy(tail, buf, baselen); | |
112 | buf[baselen] = 0; | |
113 | base = intern(buf); | |
114 | if ((fi = ht_lookup(basetab, base)) != NULL) { | |
115 | if (fi->fi_srcfile != yyfile) { | |
116 | showprev("note: ", fi); | |
117 | error("is overriden by %s", path); | |
118 | errors--; /* take it away */ | |
119 | fi->fi_flags |= FI_HIDDEN; | |
120 | } else { | |
121 | showprev("", fi); | |
122 | error("collides with %s (both make %s.o)", | |
123 | path, base); | |
124 | goto bad; | |
125 | } | |
126 | } | |
127 | ||
128 | /* | |
129 | * Commit this file to memory. | |
130 | */ | |
131 | fi = emalloc(sizeof *fi); | |
132 | fi->fi_next = NULL; | |
133 | fi->fi_srcfile = yyfile; | |
134 | fi->fi_srcline = currentline(); | |
135 | fi->fi_flags = flags; | |
136 | fi->fi_lastc = dotp[strlen(dotp) - 1]; | |
137 | fi->fi_path = path; | |
138 | fi->fi_tail = tail; | |
139 | fi->fi_base = base; | |
140 | fi->fi_opt = opts; | |
141 | fi->fi_mkrule = rule; | |
142 | if (ht_insert(pathtab, path, fi)) | |
143 | panic("addfile: ht_insert(%s)", path); | |
144 | (void)ht_replace(basetab, base, fi); | |
145 | *nextfile = fi; | |
146 | nextfile = &fi->fi_next; | |
147 | return; | |
148 | bad: | |
149 | nvfreel(opts); | |
150 | } | |
151 | ||
152 | /* | |
153 | * We have finished reading some "files" file, either ../../conf/files | |
154 | * or ./files.$machine. Make sure that everything that is flagged as | |
155 | * needing a count is reasonable. (This prevents ../../conf/files from | |
156 | * depending on some machine-specific device.) | |
157 | */ | |
158 | void | |
159 | checkfiles() | |
160 | { | |
161 | register struct files *fi, *last; | |
162 | register struct nvlist *nv; | |
163 | ||
164 | last = NULL; | |
165 | for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) { | |
166 | if ((fi->fi_flags & FI_NEEDSCOUNT) == 0) | |
167 | continue; | |
168 | for (nv = fi->fi_opt; nv != NULL; nv = nv->nv_next) | |
169 | if (ht_lookup(devbasetab, nv->nv_name) == NULL) { | |
170 | xerror(fi->fi_srcfile, fi->fi_srcline, | |
171 | "`%s' is not a countable device", | |
172 | nv->nv_name); | |
173 | /* keep fixfiles() from complaining again */ | |
174 | fi->fi_flags |= FI_HIDDEN; | |
175 | } | |
176 | } | |
177 | if (last != NULL) | |
178 | unchecked = &last->fi_next; | |
179 | } | |
180 | ||
181 | /* | |
182 | * We have finished reading everything. Tack the files down: calculate | |
183 | * selection and counts as needed. | |
184 | */ | |
185 | int | |
186 | fixfiles() | |
187 | { | |
188 | register struct files *fi; | |
189 | register struct nvlist *nv; | |
190 | register struct devbase *dev; | |
191 | int sel, err; | |
192 | ||
193 | err = 0; | |
194 | for (fi = allfiles; fi != NULL; fi = fi->fi_next) { | |
195 | if (fi->fi_flags & FI_HIDDEN) | |
196 | continue; | |
197 | if ((nv = fi->fi_opt) == NULL) { /* standard */ | |
198 | fi->fi_flags |= FI_SEL; | |
199 | continue; | |
200 | } | |
201 | /* figure out whether it is selected */ | |
202 | sel = 0; | |
203 | if (fi->fi_flags & FI_NEEDSCOUNT) { | |
204 | /* ... and compute counts too */ | |
205 | do { | |
206 | dev = ht_lookup(devbasetab, nv->nv_name); | |
207 | if (dev == NULL) { | |
208 | xerror(fi->fi_srcfile, fi->fi_srcline, | |
209 | "`%s' is not a countable device", | |
210 | nv->nv_name); | |
211 | err = 1; | |
212 | } else { | |
213 | if (dev->d_umax) | |
214 | sel = 1; | |
215 | nv->nv_int = dev->d_umax; | |
216 | (void)ht_insert(needcnttab, | |
217 | nv->nv_name, nv); | |
218 | } | |
219 | } while ((nv = nv->nv_next) != NULL); | |
220 | } else { | |
221 | do { | |
222 | if (ht_lookup(selecttab, nv->nv_name)) { | |
223 | sel = 1; | |
224 | break; | |
225 | } | |
226 | } while ((nv = nv->nv_next) != NULL); | |
227 | if (fi->fi_flags & FI_NEEDSFLAG) | |
228 | for (nv = fi->fi_opt; nv; nv = nv->nv_next) | |
229 | nv->nv_int = sel; | |
230 | } | |
231 | /* if selected, we are go */ | |
232 | if (sel) | |
233 | fi->fi_flags |= FI_SEL; | |
234 | } | |
235 | return (err); | |
236 | } |