1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * rep.c
28 *
29 * This file handles the .nse_depinfo file
30 */
31
32 /*
33 * Included files
34 */
35 #include <mk/defs.h>
36 #include <mksh/misc.h> /* retmem() */
37 #include <vroot/report.h> /* NSE_DEPINFO */
38
39 /*
40 * Static variables
41 */
42 static Recursive_make recursive_list;
43 static Recursive_make *bpatch = &recursive_list;
44 static Boolean changed;
45
46 /*
47 * File table of contents
48 */
49
50
51 /*
52 * report_recursive_init()
53 *
54 * Read the .nse_depinfo file and make a list of all the
55 * .RECURSIVE entries.
56 *
57 * Parameters:
58 *
59 * Static variables used:
60 * bpatch Points to slot where next cell should be added
61 *
62 * Global variables used:
63 * recursive_name The Name ".RECURSIVE", compared against
64 */
65
66 void
report_recursive_init(void)67 report_recursive_init(void)
68 {
69 char *search_dir;
70 char nse_depinfo[MAXPATHLEN];
71 FILE *fp;
72 int line_size, line_index;
73 wchar_t *line;
74 wchar_t *bigger_line;
75 wchar_t *colon;
76 wchar_t *dollar;
77 Recursive_make rp;
78
79 /*
80 * This routine can be called more than once, don't do
81 * anything after the first time.
82 */
83 if (depinfo_already_read) {
84 return;
85 } else {
86 depinfo_already_read = true;
87 }
88
89 search_dir = getenv("NSE_DEP");
90 if (search_dir == NULL) {
91 return;
92 }
93 (void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
94 fp = fopen(nse_depinfo, "r");
95 if (fp == NULL) {
96 return;
97 }
98 line_size = MAXPATHLEN;
99 line_index = line_size - 1;
100 line = ALLOC_WC(line_size);
101 Wstring rns(recursive_name);
102 wchar_t * wcb = rns.get_string();
103 while (fgetws(line, line_size, fp) != NULL) {
104 while (wcslen(line) == line_index) {
105 if (line[wcslen(line) - 1] == '\n') {
106 continue;
107 }
108 bigger_line = ALLOC_WC(2 * line_size);
109 wcscpy(bigger_line, line);
110 retmem(line);
111 line = bigger_line;
112 if (fgetws(&line[line_index], line_size, fp) == NULL)
113 continue;
114 line_index = 2 * line_index;
115 line_size = 2 * line_size;
116 }
117
118 colon = (wchar_t *) wcschr(line, (int) colon_char);
119 if (colon == NULL) {
120 continue;
121 }
122 dollar = (wchar_t *) wcschr(line, (int) dollar_char);
123 line[wcslen(line) - 1] = (int) nul_char;
124 if (IS_WEQUALN(&colon[2], wcb,
125 (int) recursive_name->hash.length)) {
126 /*
127 * If this entry is an old entry, ignore it
128 */
129 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
130 if (dollar == NULL ||
131 !IS_WEQUALN(wcs_buffer, (dollar+1) - VER_LEN, VER_LEN)){
132 continue;
133 }
134 rp = ALLOC(Recursive_make);
135 (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
136 /*
137 * set conditional_macro_string if string is present
138 */
139 rp->oldline = (wchar_t *) wcsdup(line);
140 if ( dollar != NULL ){
141 rp->cond_macrostring =
142 (wchar_t *) wcsdup(dollar - VER_LEN + 1);
143 }
144 /*
145 * get target name into recursive struct
146 */
147 *colon = (int) nul_char;
148 rp->target = (wchar_t *) wcsdup(line);
149 *bpatch = rp;
150 bpatch = &rp->next;
151 }
152 }
153 (void) fclose(fp);
154 }
155
156 /*
157 * report_recursive_dep(target, line)
158 *
159 * Report a target as recursive.
160 *
161 * Parameters:
162 * line Dependency line reported
163 *
164 * Static variables used:
165 * bpatch Points to slot where next cell should be added
166 * changed Written if report set changed
167 */
168 void
report_recursive_dep(Name target,wchar_t * line)169 report_recursive_dep(Name target, wchar_t *line)
170 {
171 Recursive_make rp;
172 wchar_t rec_buf[STRING_BUFFER_LENGTH];
173 String_rec string;
174
175 INIT_STRING_FROM_STACK(string, rec_buf);
176 cond_macros_into_string(target, &string);
177 /*
178 * find an applicable recursive entry, if there isn't one, create it
179 */
180 rp = find_recursive_target(target);
181 if (rp == NULL) {
182 rp = ALLOC(Recursive_make);
183 (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
184 wchar_t * wcb = get_wstring(target->string_mb); // XXX Tolik: needs retmem
185 rp->target = wcb;
186 rp->newline = (wchar_t *) wcsdup(line);
187 rp->cond_macrostring = (wchar_t *) wcsdup(rec_buf);
188 *bpatch = rp;
189 bpatch = &rp->next;
190 changed = true;
191 } else {
192 if ((rp->oldline != NULL) && !IS_WEQUAL(rp->oldline, line)) {
193 rp->newline = (wchar_t *) wcsdup(line);
194 changed = true;
195 }
196 rp->removed = false;
197 }
198 }
199
200 /*
201 * find_recursive_target(target)
202 *
203 * Search the list for a given target.
204 *
205 * Return value:
206 * The target cell
207 *
208 * Parameters:
209 * target The target we need
210 * top_level_target more info used to determinde the
211 * target we need
212 *
213 * Static variables used:
214 * recursive_list The list of targets
215 */
216 Recursive_make
find_recursive_target(Name target)217 find_recursive_target(Name target)
218 {
219 Recursive_make rp;
220 String_rec string;
221 wchar_t rec_buf[STRING_BUFFER_LENGTH];
222
223 INIT_STRING_FROM_STACK(string, rec_buf);
224 cond_macros_into_string(target, &string);
225
226 Wstring tstr(target);
227 wchar_t * wcb = tstr.get_string();
228 for (rp = recursive_list; rp != NULL; rp = rp->next) {
229 /*
230 * If this entry has already been removed, ignore it.
231 */
232 if (rp->removed)
233 continue;
234 /*
235 * If this target, and the target on the list are the same
236 * and if one of them contains conditional macro info, while
237 * the other doesn't, remove this entry from the list of
238 * recursive entries. This can only happen if the Makefile
239 * has changed to no longer contain conditional macros.
240 */
241 if (IS_WEQUAL(rp->target, wcb)) {
242 if (rp->cond_macrostring[VER_LEN] == '\0' &&
243 string.buffer.start[VER_LEN] != '\0'){
244 rp->removed = true;
245 continue;
246 } else if (rp->cond_macrostring[VER_LEN] != '\0' &&
247 string.buffer.start[VER_LEN] == '\0'){
248 rp->removed = true;
249 continue;
250 }
251 }
252 /*
253 * If this is not a VERS2 entry, only need to match
254 * the target name. toptarg information from VERS1 entries
255 * are ignored.
256 */
257 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
258 if (IS_WEQUALN(wcs_buffer, string.buffer.start, VER_LEN)) {
259 if (IS_WEQUAL(rp->cond_macrostring,
260 string.buffer.start) &&
261 IS_WEQUAL(rp->target, wcb)) {
262 return rp;
263 }
264 } else {
265 if (IS_WEQUAL(rp->target, wcb)) {
266 return rp;
267 }
268 }
269 }
270 return NULL;
271 }
272
273 /*
274 * remove_recursive_dep(target, top_level_target)
275 *
276 * Mark a target as no longer recursive.
277 *
278 * Parameters:
279 * target The target we want to remove
280 * top_level_target target we want to remove must be built from
281 * the same top level target
282 *
283 * Static variables used:
284 * changed Written if report set changed
285 */
286 void
remove_recursive_dep(Name target)287 remove_recursive_dep(Name target)
288 {
289 Recursive_make rp;
290
291 rp = find_recursive_target(target);
292
293 if ( rp != NULL ) {
294 rp->removed = true;
295 changed = true;
296 if(rp->target) {
297 retmem(rp->target);
298 rp->target = NULL;
299 }
300 if(rp->newline) {
301 retmem(rp->newline);
302 rp->newline = NULL;
303 }
304 if(rp->oldline) {
305 retmem(rp->oldline);
306 rp->oldline = NULL;
307 }
308 if(rp->cond_macrostring) {
309 retmem(rp->cond_macrostring);
310 rp->cond_macrostring = NULL;
311 }
312 }
313 }
314
315
316 /* gather_recursive_deps()
317 *
318 * Create or update list of recursive targets.
319 */
320 void
gather_recursive_deps(void)321 gather_recursive_deps(void)
322 {
323 Name_set::iterator np, e;
324 String_rec rec;
325 wchar_t rec_buf[STRING_BUFFER_LENGTH];
326 register Property lines;
327 Boolean has_recursive;
328 Dependency dp;
329
330 report_recursive_init();
331
332 /* Go thru all targets and dump recursive dependencies */
333 for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
334 if (np->has_recursive_dependency){
335 has_recursive = false;
336 /*
337 * start .RECURSIVE line with target:
338 */
339 INIT_STRING_FROM_STACK(rec, rec_buf);
340 APPEND_NAME(np, &rec, FIND_LENGTH);
341 append_char((int) colon_char, &rec);
342 append_char((int) space_char, &rec);
343
344 for (lines = get_prop(np->prop,recursive_prop);
345 lines != NULL;
346 lines = get_prop(lines->next, recursive_prop)) {
347 /*
348 * if entry is already in depinfo
349 * file or entry was not built, ignore it
350 */
351 if (lines->body.recursive.in_depinfo)
352 continue;
353 if (!lines->body.recursive.has_built)
354 continue;
355 has_recursive = true;
356 lines->body.recursive.in_depinfo=true;
357
358 /*
359 * Write the remainder of the
360 * .RECURSIVE line
361 */
362 APPEND_NAME(recursive_name, &rec,
363 FIND_LENGTH);
364 append_char((int) space_char, &rec);
365 APPEND_NAME(lines->body.recursive.directory,
366 &rec, FIND_LENGTH);
367 append_char((int) space_char, &rec);
368 APPEND_NAME(lines->body.recursive.target,
369 &rec, FIND_LENGTH);
370 append_char((int) space_char, &rec);
371
372 /* Complete list of makefiles used */
373 for (dp = lines->body.recursive.makefiles;
374 dp != NULL;
375 dp = dp->next) {
376 APPEND_NAME(dp->name, &rec, FIND_LENGTH);
377 append_char((int) space_char, &rec);
378 }
379 }
380 /*
381 * dump list of conditional targets,
382 * and report recursive entry, if needed
383 */
384 cond_macros_into_string(np, &rec);
385 if (has_recursive){
386 report_recursive_dep(np, rec.buffer.start);
387 }
388
389 } else if ( np->has_built ) {
390 remove_recursive_dep(np);
391 }
392 }
393 }
394
395