--- /dev/null	2015-05-20 11:04:11.000000000 -0400
+++ new/usr/src/cmd/make/bin/make/common/rep.cc	2015-05-20 11:04:11.294538992 -0400
@@ -0,0 +1,529 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)rep.cc 1.25 06/12/12
+ */
+
+#pragma	ident	"@(#)rep.cc	1.25	06/12/12"
+
+/*
+ *	rep.c
+ *
+ *	This file handles the .nse_depinfo file
+ */
+
+/*
+ * Included files
+ */ 
+#include <mk/defs.h>
+#include <mksh/misc.h>		/* retmem() */
+#include <vroot/report.h>	/* NSE_DEPINFO */
+
+/*
+ * Static variables
+ */
+static	Recursive_make	recursive_list;
+static	Recursive_make	*bpatch = &recursive_list;
+static	Boolean		changed;
+
+/*
+ * File table of contents
+ */
+
+
+/*
+ *	report_recursive_init()
+ *
+ *	Read the .nse_depinfo file and make a list of all the
+ *	.RECURSIVE entries.
+ *
+ *	Parameters:
+ *
+ *	Static variables used:
+ *		bpatch		Points to slot where next cell should be added
+ *
+ *	Global variables used:
+ *		recursive_name	The Name ".RECURSIVE", compared against
+ */
+
+void
+report_recursive_init(void)
+{
+	char		*search_dir;
+	char		nse_depinfo[MAXPATHLEN];
+	FILE		*fp;
+	int		line_size, line_index;
+	wchar_t		*line;
+	wchar_t		*bigger_line;
+	wchar_t		*colon;
+	wchar_t		*dollar; 
+	Recursive_make	rp;
+
+	/*
+	 * This routine can be called more than once,  don't do
+	 * anything after the first time.
+	 */
+	if (depinfo_already_read) {
+		return;
+	} else {
+		depinfo_already_read = true;
+	}
+					
+	search_dir = getenv(NOCATGETS("NSE_DEP"));
+	if (search_dir == NULL) {
+		return;
+	}
+	(void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
+	fp = fopen(nse_depinfo, "r");
+	if (fp == NULL) {
+		return;
+	}
+	line_size = MAXPATHLEN;
+	line_index = line_size - 1;
+	line = ALLOC_WC(line_size);
+	Wstring rns(recursive_name);
+	wchar_t * wcb = rns.get_string();
+	while (fgetws(line, line_size, fp) != NULL) {
+		while (wslen(line) == line_index) {
+			if (line[wslen(line) - 1] == '\n') {
+				continue;
+			}
+			bigger_line = ALLOC_WC(2 * line_size);
+			wscpy(bigger_line, line);
+			retmem(line);
+			line = bigger_line;
+			if (fgetws(&line[line_index], line_size, fp) == NULL)
+				continue;
+			line_index = 2 * line_index;
+			line_size = 2 * line_size;
+		}
+
+		colon = (wchar_t *) wschr(line, (int) colon_char);
+		if (colon == NULL) {
+			continue;
+		}
+		dollar = (wchar_t *) wschr(line, (int) dollar_char);
+		line[wslen(line) - 1] = (int) nul_char;
+		if (IS_WEQUALN(&colon[2], wcb,
+	            (int) recursive_name->hash.length)) {
+			/*
+			 * If this entry is an old entry, ignore it
+			 */
+			MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
+			if (dollar == NULL ||
+			    !IS_WEQUALN(wcs_buffer, (dollar+1) - VER_LEN, VER_LEN)){
+				continue;
+			    }
+			rp = ALLOC(Recursive_make);
+			(void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
+			/*
+			 * set conditional_macro_string if string is present
+			 */
+			rp->oldline = (wchar_t *) wsdup(line);
+			if ( dollar != NULL ){
+				rp->cond_macrostring = 
+				    (wchar_t *) wsdup(dollar - VER_LEN + 1);
+			}
+			/* 
+			 * get target name into recursive struct
+			 */
+			*colon = (int) nul_char;
+			rp->target = (wchar_t *) wsdup(line);
+			*bpatch = rp;
+			bpatch = &rp->next;
+		}
+	}
+	(void) fclose(fp);
+}
+
+/*
+ *	report_recursive_dep(target, line)
+ *
+ *	Report a target as recursive.
+ *
+ *	Parameters:
+ *		line		Dependency line reported
+ *
+ *	Static variables used:
+ *		bpatch		Points to slot where next cell should be added
+ *		changed		Written if report set changed
+ */
+void
+report_recursive_dep(Name target, wchar_t *line)
+{
+	Recursive_make	rp;
+	wchar_t		rec_buf[STRING_BUFFER_LENGTH];
+	String_rec	string;
+
+	INIT_STRING_FROM_STACK(string, rec_buf);
+	cond_macros_into_string(target, &string);
+	/* 
+	 * find an applicable recursive entry, if there isn't one, create it
+	 */
+	rp = find_recursive_target(target);
+	if (rp == NULL) {
+		rp = ALLOC(Recursive_make);
+		(void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
+		wchar_t * wcb = get_wstring(target->string_mb); // XXX Tolik: needs retmem
+                rp->target = wcb;
+		rp->newline = (wchar_t *) wsdup(line);
+		rp->cond_macrostring = (wchar_t *) wsdup(rec_buf);
+		*bpatch = rp;
+		bpatch = &rp->next;
+		changed = true;
+	} else {
+		if ((rp->oldline != NULL) && !IS_WEQUAL(rp->oldline, line)) {
+			rp->newline = (wchar_t *) wsdup(line);
+			changed = true;
+		}
+		rp->removed = false;
+	}
+}
+
+/*
+ *	find_recursive_target(target)
+ *
+ *	Search the list for a given target.
+ *
+ *	Return value:
+ *				The target cell
+ *
+ *	Parameters:
+ *		target		The target we need
+ *		top_level_target more info used to determinde the 
+ *				 target we need
+ *
+ *	Static variables used:
+ *		recursive_list	The list of targets
+ */
+Recursive_make
+find_recursive_target(Name target)
+{
+	Recursive_make	rp;
+	String_rec	string;
+	wchar_t		rec_buf[STRING_BUFFER_LENGTH]; 
+
+	INIT_STRING_FROM_STACK(string, rec_buf);
+	cond_macros_into_string(target, &string);
+
+	Wstring tstr(target);
+	wchar_t * wcb = tstr.get_string();
+	for (rp = recursive_list; rp != NULL; rp = rp->next) {
+		/* 
+		 * If this entry has already been removed, ignore it.
+		 */
+		if (rp->removed)
+			continue;
+		/* 
+		 * If this target, and the target on the list are the same
+		 * and if one of them contains conditional macro info, while
+		 * the other doesn't,  remove this entry from the list of
+		 * recursive entries.  This can only happen if the Makefile
+		 * has changed to no longer contain conditional macros.
+		 */
+		if (IS_WEQUAL(rp->target, wcb)) {
+			if (rp->cond_macrostring[VER_LEN] == '\0' &&
+			    string.buffer.start[VER_LEN] != '\0'){
+				rp->removed = true;
+				continue;
+			} else if (rp->cond_macrostring[VER_LEN] != '\0' &&
+			    string.buffer.start[VER_LEN] == '\0'){
+				rp->removed = true;
+				continue;
+			} 
+		}
+		/*
+		 * If this is not a VERS2 entry,  only need to match
+		 * the target name.  toptarg information from VERS1 entries
+		 * are ignored.
+		 */
+		MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
+		if (IS_WEQUALN(wcs_buffer, string.buffer.start, VER_LEN)) { 
+			if (IS_WEQUAL(rp->cond_macrostring, 
+			    string.buffer.start) &&
+			    IS_WEQUAL(rp->target, wcb)) {
+				return rp;
+			}
+		} else {
+			if (IS_WEQUAL(rp->target, wcb)) {
+				return rp;
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+ *	remove_recursive_dep(target, top_level_target)
+ *
+ *	Mark a target as no longer recursive.
+ *
+ *	Parameters:
+ *		target		The target we want to remove
+ *		top_level_target target we want to remove must be built from 
+ *				 the same top level target
+ *
+ *	Static variables used:
+ *		changed		Written if report set changed
+ */
+void
+remove_recursive_dep(Name target)
+{
+	Recursive_make	rp;
+
+	rp = find_recursive_target(target);
+
+	if ( rp != NULL ) {
+		rp->removed = true;	
+		changed = true;
+		if(rp->target) {
+			retmem(rp->target);
+			rp->target = NULL;
+		}
+		if(rp->newline) {
+			retmem(rp->newline);
+			rp->newline = NULL;
+		}
+		if(rp->oldline) {
+			retmem(rp->oldline);
+			rp->oldline = NULL;
+		}
+		if(rp->cond_macrostring) {
+			retmem(rp->cond_macrostring);
+			rp->cond_macrostring = NULL;
+		}
+	}
+}
+
+#ifdef NSE
+/*
+ *	report_recursive_done()
+ *
+ *	Write the .nse_depinfo file.
+ *
+ *	Parameters:
+ *
+ *	Static variables used:
+ *		recursive_list	The list of targets
+ *		changed		Written if report set changed
+ *
+ *	Global variables used:
+ *		recursive_name	The Name ".RECURSIVE", compared against
+ */
+void
+report_recursive_done(void)
+{
+	char		*search_dir;
+	char		nse_depinfo[MAXPATHLEN];
+	char		tmpfile[MAXPATHLEN];
+	FILE		*ofp;
+	FILE		*ifp;
+	wchar_t		*space;
+	wchar_t		*data;
+	wchar_t		*line;
+	wchar_t		*bigger_line;
+	int		line_size, line_index;
+	int		lock_err;
+	Recursive_make	rp;
+
+	if (changed == false) {
+		return;
+	}
+
+	search_dir = getenv(NOCATGETS("NSE_DEP"));
+	if (search_dir == NULL) {
+		return;
+	}
+	(void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
+	(void) sprintf(tmpfile, "%s.%d", nse_depinfo, getpid());
+	ofp = fopen(tmpfile, "w");
+	if (ofp == NULL) {
+		(void) fprintf(stderr,
+			       catgets(catd, 1, 116, "Cannot open `%s' for writing\n"),
+			       tmpfile);
+		return;
+	}
+	(void) sprintf(nse_depinfo_lockfile, 
+		       "%s/%s", search_dir, NSE_DEPINFO_LOCK);
+	if (lock_err = file_lock(nse_depinfo, 
+				 nse_depinfo_lockfile, 
+				 (int *) &nse_depinfo_locked, 0)) {
+		(void) fprintf(stderr,
+			       catgets(catd, 1, 117, "writing .RECURSIVE lines to %s\n"),
+			       tmpfile);
+		(void) fprintf(stderr,
+			       catgets(catd, 1, 118, "To recover, merge .nse_depinfo.%d with .nse_depinfo\n"),
+			       getpid(),
+			       catgets(catd, 1, 119, "with .nse_depinfo"));
+	}
+
+	if (nse_depinfo_locked) {
+		ifp = fopen(nse_depinfo, "r");
+		if (ifp != NULL) {
+			/*
+			 * Copy all the non-.RECURSIVE lines from 
+			 * the old file to the new one.
+			 */
+			line_size = MAXPATHLEN;
+			line_index = line_size - 1;
+			line = ALLOC_WC(line_size);
+			while (fgetws(line, line_size, ifp) != NULL) {
+				while (wslen(line) == line_index) {
+					if (line[wslen(line) - 1] == '\n') {
+						continue;
+					}
+					bigger_line = ALLOC_WC(2 * line_size);
+					wscpy(bigger_line, line);
+					retmem(line);
+					line = bigger_line;
+					if (fgetws(&line[line_index], 
+						  line_size, ifp) == NULL)
+					  continue;
+					line_index = 2 * line_index;
+					line_size = 2 * line_size;
+				}
+
+				space = wschr(line, (int) space_char);
+				if (space != NULL && 
+				    IS_WEQUALN(&space[1],
+					      recursive_name->string,
+					      (int) recursive_name->hash.length)) {
+					continue;
+				}
+				WCSTOMBS(mbs_buffer, line);
+				(void) fprintf(ofp, "%s", mbs_buffer);
+			}
+			(void) fclose(ifp);
+		}
+	}
+
+	/*
+	 * Write out the .RECURSIVE lines.
+	 */
+	for (rp = recursive_list; rp != NULL; rp = rp->next) {
+		if (rp->removed) {
+			continue;
+		}
+		if (rp->newline != NULL) {
+			data = rp->newline;
+		} else {
+			data = rp->oldline;
+		}
+		if (data != NULL) {
+			WCSTOMBS(mbs_buffer, data);
+			(void) fprintf(ofp, "%s\n", mbs_buffer);
+		}
+	}
+	(void) fclose(ofp);
+
+	if (nse_depinfo_locked) {
+		(void) rename(tmpfile, nse_depinfo);
+		(void) unlink(nse_depinfo_lockfile);
+		nse_depinfo_locked = false;
+		nse_depinfo_lockfile[0] = '\0';
+		(void) chmod(nse_depinfo, 0666);
+	}
+}
+#endif // NSE
+
+/* gather_recursive_deps()
+ *
+ *	Create or update list of recursive targets.  
+ */
+void
+gather_recursive_deps(void)
+{
+	Name_set::iterator	np, e;
+	String_rec		rec;
+	wchar_t			rec_buf[STRING_BUFFER_LENGTH];
+	register Property	lines;
+	Boolean			has_recursive;
+	Dependency		dp;
+
+	report_recursive_init();
+
+	/* Go thru all targets and dump recursive dependencies */
+	for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
+		if (np->has_recursive_dependency){
+			has_recursive = false;
+			/* 
+			 * start .RECURSIVE line with target:
+			 */
+			INIT_STRING_FROM_STACK(rec, rec_buf);
+			APPEND_NAME(np, &rec, FIND_LENGTH);
+			append_char((int) colon_char, &rec);
+			append_char((int) space_char, &rec);
+			
+			for (lines = get_prop(np->prop,recursive_prop); 
+			    lines != NULL;
+			    lines = get_prop(lines->next, recursive_prop)) {
+				/* 
+				 * if entry is already in depinfo
+				 * file or entry was not built, ignore it
+				 */
+				if (lines->body.recursive.in_depinfo)
+					continue;
+				if (!lines->body.recursive.has_built)
+					continue;
+				has_recursive = true;
+				lines->body.recursive.in_depinfo=true;
+				
+				/* 
+				* Write the remainder of the
+				* .RECURSIVE line 
+				*/
+				APPEND_NAME(recursive_name, &rec, 
+				    FIND_LENGTH);
+				append_char((int) space_char, &rec);
+				APPEND_NAME(lines->body.recursive.directory,
+					&rec, FIND_LENGTH);
+				append_char((int) space_char, &rec);
+				APPEND_NAME(lines->body.recursive.target,
+					&rec, FIND_LENGTH);
+				append_char((int) space_char, &rec);
+				
+				/* Complete list of makefiles used */
+				for (dp = lines->body.recursive.makefiles; 
+				    dp != NULL; 
+				    dp = dp->next) {
+					APPEND_NAME(dp->name, &rec,  FIND_LENGTH);
+					append_char((int) space_char, &rec);
+				}
+			}  
+			/* 
+			 * dump list of conditional targets,
+			 * and report recursive entry, if needed
+			 */
+			cond_macros_into_string(np, &rec);
+			if (has_recursive){
+				report_recursive_dep(np, rec.buffer.start);
+			}
+
+		} else if ( np->has_built ) {
+			remove_recursive_dep(np);
+		}
+	}
+}
+
