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 */
42static	Recursive_make	recursive_list;
43static	Recursive_make	*bpatch = &recursive_list;
44static	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
66void
67report_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 */
168void
169report_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 */
216Recursive_make
217find_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 */
286void
287remove_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 */
320void
321gather_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