xref: /titanic_51/usr/src/cmd/make/bin/files.cc (revision 10d63b7db37a83b39c7f511cf9426c9d03ea0760)
1*10d63b7dSRichard Lowe /*
2*10d63b7dSRichard Lowe  * CDDL HEADER START
3*10d63b7dSRichard Lowe  *
4*10d63b7dSRichard Lowe  * The contents of this file are subject to the terms of the
5*10d63b7dSRichard Lowe  * Common Development and Distribution License (the "License").
6*10d63b7dSRichard Lowe  * You may not use this file except in compliance with the License.
7*10d63b7dSRichard Lowe  *
8*10d63b7dSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10d63b7dSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10*10d63b7dSRichard Lowe  * See the License for the specific language governing permissions
11*10d63b7dSRichard Lowe  * and limitations under the License.
12*10d63b7dSRichard Lowe  *
13*10d63b7dSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14*10d63b7dSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10d63b7dSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16*10d63b7dSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17*10d63b7dSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10d63b7dSRichard Lowe  *
19*10d63b7dSRichard Lowe  * CDDL HEADER END
20*10d63b7dSRichard Lowe  */
21*10d63b7dSRichard Lowe /*
22*10d63b7dSRichard Lowe  * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23*10d63b7dSRichard Lowe  * Use is subject to license terms.
24*10d63b7dSRichard Lowe  */
25*10d63b7dSRichard Lowe 
26*10d63b7dSRichard Lowe /*
27*10d63b7dSRichard Lowe  *	files.c
28*10d63b7dSRichard Lowe  *
29*10d63b7dSRichard Lowe  *	Various file related routines:
30*10d63b7dSRichard Lowe  *		Figure out if file exists
31*10d63b7dSRichard Lowe  *		Wildcard resolution for directory reader
32*10d63b7dSRichard Lowe  *		Directory reader
33*10d63b7dSRichard Lowe  */
34*10d63b7dSRichard Lowe 
35*10d63b7dSRichard Lowe 
36*10d63b7dSRichard Lowe /*
37*10d63b7dSRichard Lowe  * Included files
38*10d63b7dSRichard Lowe  */
39*10d63b7dSRichard Lowe #include <dirent.h>		/* opendir() */
40*10d63b7dSRichard Lowe #include <errno.h>		/* errno */
41*10d63b7dSRichard Lowe #include <mk/defs.h>
42*10d63b7dSRichard Lowe #include <mksh/macro.h>		/* getvar() */
43*10d63b7dSRichard Lowe #include <mksh/misc.h>		/* get_prop(), append_prop() */
44*10d63b7dSRichard Lowe #include <sys/stat.h>		/* lstat() */
45*10d63b7dSRichard Lowe #include <libintl.h>
46*10d63b7dSRichard Lowe 
47*10d63b7dSRichard Lowe /*
48*10d63b7dSRichard Lowe  * Defined macros
49*10d63b7dSRichard Lowe  */
50*10d63b7dSRichard Lowe 
51*10d63b7dSRichard Lowe /*
52*10d63b7dSRichard Lowe  * typedefs & structs
53*10d63b7dSRichard Lowe  */
54*10d63b7dSRichard Lowe 
55*10d63b7dSRichard Lowe /*
56*10d63b7dSRichard Lowe  * Static variables
57*10d63b7dSRichard Lowe  */
58*10d63b7dSRichard Lowe 
59*10d63b7dSRichard Lowe /*
60*10d63b7dSRichard Lowe  * File table of contents
61*10d63b7dSRichard Lowe  */
62*10d63b7dSRichard Lowe extern	timestruc_t&	exists(register Name target);
63*10d63b7dSRichard Lowe extern  void		set_target_stat(register Name target, struct stat buf);
64*10d63b7dSRichard Lowe static	timestruc_t&	vpath_exists(register Name target);
65*10d63b7dSRichard Lowe static	Name		enter_file_name(wchar_t *name_string, wchar_t *library);
66*10d63b7dSRichard Lowe static	Boolean		star_match(register char *string, register char *pattern);
67*10d63b7dSRichard Lowe static	Boolean		amatch(register wchar_t *string, register wchar_t *pattern);
68*10d63b7dSRichard Lowe 
69*10d63b7dSRichard Lowe /*
70*10d63b7dSRichard Lowe  *	exists(target)
71*10d63b7dSRichard Lowe  *
72*10d63b7dSRichard Lowe  *	Figure out the timestamp for one target.
73*10d63b7dSRichard Lowe  *
74*10d63b7dSRichard Lowe  *	Return value:
75*10d63b7dSRichard Lowe  *				The time the target was created
76*10d63b7dSRichard Lowe  *
77*10d63b7dSRichard Lowe  *	Parameters:
78*10d63b7dSRichard Lowe  *		target		The target to check
79*10d63b7dSRichard Lowe  *
80*10d63b7dSRichard Lowe  *	Global variables used:
81*10d63b7dSRichard Lowe  *		debug_level	Should we trace the stat call?
82*10d63b7dSRichard Lowe  *		recursion_level	Used for tracing
83*10d63b7dSRichard Lowe  *		vpath_defined	Was the variable VPATH defined in environment?
84*10d63b7dSRichard Lowe  */
85*10d63b7dSRichard Lowe timestruc_t&
86*10d63b7dSRichard Lowe exists(register Name target)
87*10d63b7dSRichard Lowe {
88*10d63b7dSRichard Lowe 	struct stat		buf;
89*10d63b7dSRichard Lowe 	register int		result;
90*10d63b7dSRichard Lowe 
91*10d63b7dSRichard Lowe 	/* We cache stat information. */
92*10d63b7dSRichard Lowe 	if (target->stat.time != file_no_time) {
93*10d63b7dSRichard Lowe 		return target->stat.time;
94*10d63b7dSRichard Lowe 	}
95*10d63b7dSRichard Lowe 
96*10d63b7dSRichard Lowe 	/*
97*10d63b7dSRichard Lowe 	 * If the target is a member, we have to extract the time
98*10d63b7dSRichard Lowe 	 * from the archive.
99*10d63b7dSRichard Lowe 	 */
100*10d63b7dSRichard Lowe 	if (target->is_member &&
101*10d63b7dSRichard Lowe 	    (get_prop(target->prop, member_prop) != NULL)) {
102*10d63b7dSRichard Lowe 		return read_archive(target);
103*10d63b7dSRichard Lowe 	}
104*10d63b7dSRichard Lowe 
105*10d63b7dSRichard Lowe 	if (debug_level > 1) {
106*10d63b7dSRichard Lowe 		(void) printf("%*sstat(%s)\n",
107*10d63b7dSRichard Lowe 		              recursion_level,
108*10d63b7dSRichard Lowe 		              "",
109*10d63b7dSRichard Lowe 		              target->string_mb);
110*10d63b7dSRichard Lowe 	}
111*10d63b7dSRichard Lowe 
112*10d63b7dSRichard Lowe 	result = lstat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
113*10d63b7dSRichard Lowe 	if ((result != -1) && ((buf.st_mode & S_IFMT) == S_IFLNK)) {
114*10d63b7dSRichard Lowe                 /*
115*10d63b7dSRichard Lowe 		 * If the file is a symbolic link, we remember that
116*10d63b7dSRichard Lowe 		 * and then we get the status for the refd file.
117*10d63b7dSRichard Lowe 		 */
118*10d63b7dSRichard Lowe                 target->stat.is_sym_link = true;
119*10d63b7dSRichard Lowe                 result = stat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
120*10d63b7dSRichard Lowe         } else {
121*10d63b7dSRichard Lowe                 target->stat.is_sym_link = false;
122*10d63b7dSRichard Lowe 	}
123*10d63b7dSRichard Lowe 
124*10d63b7dSRichard Lowe 	if (result < 0) {
125*10d63b7dSRichard Lowe 		target->stat.time = file_doesnt_exist;
126*10d63b7dSRichard Lowe 		target->stat.stat_errno = errno;
127*10d63b7dSRichard Lowe 		if ((errno == ENOENT) &&
128*10d63b7dSRichard Lowe 		    vpath_defined &&
129*10d63b7dSRichard Lowe /* azv, fixing bug 1262942, VPATH works with a leaf name
130*10d63b7dSRichard Lowe  * but not a directory name.
131*10d63b7dSRichard Lowe  */
132*10d63b7dSRichard Lowe 		    (target->string_mb[0] != (int) slash_char) ) {
133*10d63b7dSRichard Lowe /* BID_1214655 */
134*10d63b7dSRichard Lowe /* azv */
135*10d63b7dSRichard Lowe 			vpath_exists(target);
136*10d63b7dSRichard Lowe 			// return vpath_exists(target);
137*10d63b7dSRichard Lowe 		}
138*10d63b7dSRichard Lowe 	} else {
139*10d63b7dSRichard Lowe 		/* Save all the information we need about the file */
140*10d63b7dSRichard Lowe 		target->stat.stat_errno = 0;
141*10d63b7dSRichard Lowe 		target->stat.is_file = true;
142*10d63b7dSRichard Lowe 		target->stat.mode = buf.st_mode & 0777;
143*10d63b7dSRichard Lowe 		target->stat.size = buf.st_size;
144*10d63b7dSRichard Lowe 		target->stat.is_dir =
145*10d63b7dSRichard Lowe 		  BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
146*10d63b7dSRichard Lowe 		if (target->stat.is_dir) {
147*10d63b7dSRichard Lowe 			target->stat.time = file_is_dir;
148*10d63b7dSRichard Lowe 		} else {
149*10d63b7dSRichard Lowe 			/* target->stat.time = buf.st_mtime; */
150*10d63b7dSRichard Lowe /* BID_1129806 */
151*10d63b7dSRichard Lowe /* vis@nbsp.nsk.su */
152*10d63b7dSRichard Lowe 			target->stat.time = MAX(buf.st_mtim, file_min_time);
153*10d63b7dSRichard Lowe 		}
154*10d63b7dSRichard Lowe 	}
155*10d63b7dSRichard Lowe 	if ((target->colon_splits > 0) &&
156*10d63b7dSRichard Lowe 	    (get_prop(target->prop, time_prop) == NULL)) {
157*10d63b7dSRichard Lowe 		append_prop(target, time_prop)->body.time.time =
158*10d63b7dSRichard Lowe 		  target->stat.time;
159*10d63b7dSRichard Lowe 	}
160*10d63b7dSRichard Lowe 	return target->stat.time;
161*10d63b7dSRichard Lowe }
162*10d63b7dSRichard Lowe 
163*10d63b7dSRichard Lowe /*
164*10d63b7dSRichard Lowe  *	set_target_stat( target, buf)
165*10d63b7dSRichard Lowe  *
166*10d63b7dSRichard Lowe  *	Called by exists() to set some stat fields in the Name structure
167*10d63b7dSRichard Lowe  *	to those read by the stat_vroot() call (from disk).
168*10d63b7dSRichard Lowe  *
169*10d63b7dSRichard Lowe  *	Parameters:
170*10d63b7dSRichard Lowe  *		target		The target whose stat field is set
171*10d63b7dSRichard Lowe  *		buf		stat values (on disk) of the file
172*10d63b7dSRichard Lowe  *				represented by target.
173*10d63b7dSRichard Lowe  */
174*10d63b7dSRichard Lowe void
175*10d63b7dSRichard Lowe set_target_stat(register Name target, struct stat buf)
176*10d63b7dSRichard Lowe {
177*10d63b7dSRichard Lowe 	target->stat.stat_errno = 0;
178*10d63b7dSRichard Lowe 	target->stat.is_file = true;
179*10d63b7dSRichard Lowe 	target->stat.mode = buf.st_mode & 0777;
180*10d63b7dSRichard Lowe 	target->stat.size = buf.st_size;
181*10d63b7dSRichard Lowe 	target->stat.is_dir =
182*10d63b7dSRichard Lowe 	  BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
183*10d63b7dSRichard Lowe 	if (target->stat.is_dir) {
184*10d63b7dSRichard Lowe 		target->stat.time = file_is_dir;
185*10d63b7dSRichard Lowe 	} else {
186*10d63b7dSRichard Lowe 		/* target->stat.time = buf.st_mtime; */
187*10d63b7dSRichard Lowe /* BID_1129806 */
188*10d63b7dSRichard Lowe /* vis@nbsp.nsk.su */
189*10d63b7dSRichard Lowe 		target->stat.time = MAX(buf.st_mtim, file_min_time);
190*10d63b7dSRichard Lowe 	}
191*10d63b7dSRichard Lowe }
192*10d63b7dSRichard Lowe 
193*10d63b7dSRichard Lowe 
194*10d63b7dSRichard Lowe /*
195*10d63b7dSRichard Lowe  *	vpath_exists(target)
196*10d63b7dSRichard Lowe  *
197*10d63b7dSRichard Lowe  *	Called if exists() discovers that there is a VPATH defined.
198*10d63b7dSRichard Lowe  *	This function stats the VPATH translation of the target.
199*10d63b7dSRichard Lowe  *
200*10d63b7dSRichard Lowe  *	Return value:
201*10d63b7dSRichard Lowe  *				The time the target was created
202*10d63b7dSRichard Lowe  *
203*10d63b7dSRichard Lowe  *	Parameters:
204*10d63b7dSRichard Lowe  *		target		The target to check
205*10d63b7dSRichard Lowe  *
206*10d63b7dSRichard Lowe  *	Global variables used:
207*10d63b7dSRichard Lowe  *		vpath_name	The Name "VPATH", used to get macro value
208*10d63b7dSRichard Lowe  */
209*10d63b7dSRichard Lowe static timestruc_t&
210*10d63b7dSRichard Lowe vpath_exists(register Name target)
211*10d63b7dSRichard Lowe {
212*10d63b7dSRichard Lowe 	wchar_t			*vpath;
213*10d63b7dSRichard Lowe 	wchar_t			file_name[MAXPATHLEN];
214*10d63b7dSRichard Lowe 	wchar_t			*name_p;
215*10d63b7dSRichard Lowe 	Name			alias;
216*10d63b7dSRichard Lowe 
217*10d63b7dSRichard Lowe 	/*
218*10d63b7dSRichard Lowe 	 * To avoid recursive search through VPATH when exists(alias) is called
219*10d63b7dSRichard Lowe 	 */
220*10d63b7dSRichard Lowe 	vpath_defined = false;
221*10d63b7dSRichard Lowe 
222*10d63b7dSRichard Lowe 	Wstring wcb(getvar(vpath_name));
223*10d63b7dSRichard Lowe 	Wstring wcb1(target);
224*10d63b7dSRichard Lowe 
225*10d63b7dSRichard Lowe 	vpath = wcb.get_string();
226*10d63b7dSRichard Lowe 
227*10d63b7dSRichard Lowe 	while (*vpath != (int) nul_char) {
228*10d63b7dSRichard Lowe 		name_p = file_name;
229*10d63b7dSRichard Lowe 		while ((*vpath != (int) colon_char) &&
230*10d63b7dSRichard Lowe 		       (*vpath != (int) nul_char)) {
231*10d63b7dSRichard Lowe 			*name_p++ = *vpath++;
232*10d63b7dSRichard Lowe 		}
233*10d63b7dSRichard Lowe 		*name_p++ = (int) slash_char;
234*10d63b7dSRichard Lowe 		(void) wcscpy(name_p, wcb1.get_string());
235*10d63b7dSRichard Lowe 		alias = GETNAME(file_name, FIND_LENGTH);
236*10d63b7dSRichard Lowe 		if (exists(alias) != file_doesnt_exist) {
237*10d63b7dSRichard Lowe 			target->stat.is_file = true;
238*10d63b7dSRichard Lowe 			target->stat.mode = alias->stat.mode;
239*10d63b7dSRichard Lowe 			target->stat.size = alias->stat.size;
240*10d63b7dSRichard Lowe 			target->stat.is_dir = alias->stat.is_dir;
241*10d63b7dSRichard Lowe 			target->stat.time = alias->stat.time;
242*10d63b7dSRichard Lowe 			maybe_append_prop(target, vpath_alias_prop)->
243*10d63b7dSRichard Lowe 						body.vpath_alias.alias = alias;
244*10d63b7dSRichard Lowe 			target->has_vpath_alias_prop = true;
245*10d63b7dSRichard Lowe 			vpath_defined = true;
246*10d63b7dSRichard Lowe 			return alias->stat.time;
247*10d63b7dSRichard Lowe 		}
248*10d63b7dSRichard Lowe 		while ((*vpath != (int) nul_char) &&
249*10d63b7dSRichard Lowe 		       ((*vpath == (int) colon_char) || iswspace(*vpath))) {
250*10d63b7dSRichard Lowe 			vpath++;
251*10d63b7dSRichard Lowe 		}
252*10d63b7dSRichard Lowe 	}
253*10d63b7dSRichard Lowe 	/*
254*10d63b7dSRichard Lowe 	 * Restore vpath_defined
255*10d63b7dSRichard Lowe 	 */
256*10d63b7dSRichard Lowe 	vpath_defined = true;
257*10d63b7dSRichard Lowe 	return target->stat.time;
258*10d63b7dSRichard Lowe }
259*10d63b7dSRichard Lowe 
260*10d63b7dSRichard Lowe /*
261*10d63b7dSRichard Lowe  *	read_dir(dir, pattern, line, library)
262*10d63b7dSRichard Lowe  *
263*10d63b7dSRichard Lowe  *	Used to enter the contents of directories into makes namespace.
264*10d63b7dSRichard Lowe  *	Presence of a file is important when scanning for implicit rules.
265*10d63b7dSRichard Lowe  *	read_dir() is also used to expand wildcards in dependency lists.
266*10d63b7dSRichard Lowe  *
267*10d63b7dSRichard Lowe  *	Return value:
268*10d63b7dSRichard Lowe  *				Non-0 if we found files to match the pattern
269*10d63b7dSRichard Lowe  *
270*10d63b7dSRichard Lowe  *	Parameters:
271*10d63b7dSRichard Lowe  *		dir		Path to the directory to read
272*10d63b7dSRichard Lowe  *		pattern		Pattern for that files should match or NULL
273*10d63b7dSRichard Lowe  *		line		When we scan using a pattern we enter files
274*10d63b7dSRichard Lowe  *				we find as dependencies for this line
275*10d63b7dSRichard Lowe  *		library		If we scan for "lib.a(<wildcard-member>)"
276*10d63b7dSRichard Lowe  *
277*10d63b7dSRichard Lowe  *	Global variables used:
278*10d63b7dSRichard Lowe  *		debug_level	Should we trace the dir reading?
279*10d63b7dSRichard Lowe  *		dot		The Name ".", compared against
280*10d63b7dSRichard Lowe  *		sccs_dir_path	The path to the SCCS dir (from PROJECTDIR)
281*10d63b7dSRichard Lowe  *		vpath_defined	Was the variable VPATH defined in environment?
282*10d63b7dSRichard Lowe  *		vpath_name	The Name "VPATH", use to get macro value
283*10d63b7dSRichard Lowe  */
284*10d63b7dSRichard Lowe int
285*10d63b7dSRichard Lowe read_dir(Name dir, wchar_t *pattern, Property line, wchar_t *library)
286*10d63b7dSRichard Lowe {
287*10d63b7dSRichard Lowe 	wchar_t			file_name[MAXPATHLEN];
288*10d63b7dSRichard Lowe 	wchar_t			*file_name_p = file_name;
289*10d63b7dSRichard Lowe 	Name			file;
290*10d63b7dSRichard Lowe 	wchar_t			plain_file_name[MAXPATHLEN];
291*10d63b7dSRichard Lowe 	wchar_t			*plain_file_name_p;
292*10d63b7dSRichard Lowe 	Name			plain_file;
293*10d63b7dSRichard Lowe 	wchar_t			tmp_wcs_buffer[MAXPATHLEN];
294*10d63b7dSRichard Lowe 	DIR			*dir_fd;
295*10d63b7dSRichard Lowe 	int			m_local_dependency=0;
296*10d63b7dSRichard Lowe #define d_fileno d_ino
297*10d63b7dSRichard Lowe         register struct dirent  *dp;
298*10d63b7dSRichard Lowe 	wchar_t			*vpath = NULL;
299*10d63b7dSRichard Lowe 	wchar_t			*p;
300*10d63b7dSRichard Lowe 	int			result = 0;
301*10d63b7dSRichard Lowe 
302*10d63b7dSRichard Lowe 	if(dir->hash.length >= MAXPATHLEN) {
303*10d63b7dSRichard Lowe 		return 0;
304*10d63b7dSRichard Lowe 	}
305*10d63b7dSRichard Lowe 
306*10d63b7dSRichard Lowe 	Wstring wcb(dir);
307*10d63b7dSRichard Lowe 	Wstring vps;
308*10d63b7dSRichard Lowe 
309*10d63b7dSRichard Lowe 	/* A directory is only read once unless we need to expand wildcards. */
310*10d63b7dSRichard Lowe 	if (pattern == NULL) {
311*10d63b7dSRichard Lowe 		if (dir->has_read_dir) {
312*10d63b7dSRichard Lowe 			return 0;
313*10d63b7dSRichard Lowe 		}
314*10d63b7dSRichard Lowe 		dir->has_read_dir = true;
315*10d63b7dSRichard Lowe 	}
316*10d63b7dSRichard Lowe 	/* Check if VPATH is active and setup list if it is. */
317*10d63b7dSRichard Lowe 	if (vpath_defined && (dir == dot)) {
318*10d63b7dSRichard Lowe 		vps.init(getvar(vpath_name));
319*10d63b7dSRichard Lowe 		vpath = vps.get_string();
320*10d63b7dSRichard Lowe 	}
321*10d63b7dSRichard Lowe 
322*10d63b7dSRichard Lowe 	/*
323*10d63b7dSRichard Lowe 	 * Prepare the string where we build the full name of the
324*10d63b7dSRichard Lowe 	 * files in the directory.
325*10d63b7dSRichard Lowe 	 */
326*10d63b7dSRichard Lowe 	if ((dir->hash.length > 1) || (wcb.get_string()[0] != (int) period_char)) {
327*10d63b7dSRichard Lowe 		(void) wcscpy(file_name, wcb.get_string());
328*10d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "/");
329*10d63b7dSRichard Lowe 		(void) wcscat(file_name, wcs_buffer);
330*10d63b7dSRichard Lowe 		file_name_p = file_name + wcslen(file_name);
331*10d63b7dSRichard Lowe 	}
332*10d63b7dSRichard Lowe 
333*10d63b7dSRichard Lowe 	/* Open the directory. */
334*10d63b7dSRichard Lowe vpath_loop:
335*10d63b7dSRichard Lowe 	dir_fd = opendir(dir->string_mb);
336*10d63b7dSRichard Lowe 	if (dir_fd == NULL) {
337*10d63b7dSRichard Lowe 		return 0;
338*10d63b7dSRichard Lowe 	}
339*10d63b7dSRichard Lowe 
340*10d63b7dSRichard Lowe 	/* Read all the directory entries. */
341*10d63b7dSRichard Lowe 	while ((dp = readdir(dir_fd)) != NULL) {
342*10d63b7dSRichard Lowe 		/* We ignore "." and ".." */
343*10d63b7dSRichard Lowe 		if ((dp->d_fileno == 0) ||
344*10d63b7dSRichard Lowe 		    ((dp->d_name[0] == (int) period_char) &&
345*10d63b7dSRichard Lowe 		     ((dp->d_name[1] == 0) ||
346*10d63b7dSRichard Lowe 		      ((dp->d_name[1] == (int) period_char) &&
347*10d63b7dSRichard Lowe 		       (dp->d_name[2] == 0))))) {
348*10d63b7dSRichard Lowe 			continue;
349*10d63b7dSRichard Lowe 		}
350*10d63b7dSRichard Lowe 		/*
351*10d63b7dSRichard Lowe 		 * Build the full name of the file using whatever
352*10d63b7dSRichard Lowe 		 * path supplied to the function.
353*10d63b7dSRichard Lowe 		 */
354*10d63b7dSRichard Lowe 		MBSTOWCS(tmp_wcs_buffer, dp->d_name);
355*10d63b7dSRichard Lowe 		(void) wcscpy(file_name_p, tmp_wcs_buffer);
356*10d63b7dSRichard Lowe 		file = enter_file_name(file_name, library);
357*10d63b7dSRichard Lowe 		if ((pattern != NULL) && amatch(tmp_wcs_buffer, pattern)) {
358*10d63b7dSRichard Lowe 			/*
359*10d63b7dSRichard Lowe 			 * If we are expanding a wildcard pattern, we
360*10d63b7dSRichard Lowe 			 * enter the file as a dependency for the target.
361*10d63b7dSRichard Lowe 			 */
362*10d63b7dSRichard Lowe 			if (debug_level > 0){
363*10d63b7dSRichard Lowe 				WCSTOMBS(mbs_buffer, pattern);
364*10d63b7dSRichard Lowe 				(void) printf(gettext("'%s: %s' due to %s expansion\n"),
365*10d63b7dSRichard Lowe 					      line->body.line.target->string_mb,
366*10d63b7dSRichard Lowe 					      file->string_mb,
367*10d63b7dSRichard Lowe 					      mbs_buffer);
368*10d63b7dSRichard Lowe 			}
369*10d63b7dSRichard Lowe 			enter_dependency(line, file, false);
370*10d63b7dSRichard Lowe 			result++;
371*10d63b7dSRichard Lowe 		} else {
372*10d63b7dSRichard Lowe 			/*
373*10d63b7dSRichard Lowe 			 * If the file has an SCCS/s. file,
374*10d63b7dSRichard Lowe 			 * we will detect that later on.
375*10d63b7dSRichard Lowe 			 */
376*10d63b7dSRichard Lowe 			file->stat.has_sccs = NO_SCCS;
377*10d63b7dSRichard Lowe 		/*
378*10d63b7dSRichard Lowe 		 * If this is an s. file, we also enter it as if it
379*10d63b7dSRichard Lowe 		 * existed in the plain directory.
380*10d63b7dSRichard Lowe 		 */
381*10d63b7dSRichard Lowe 		if ((dp->d_name[0] == 's') &&
382*10d63b7dSRichard Lowe 		    (dp->d_name[1] == (int) period_char)) {
383*10d63b7dSRichard Lowe 
384*10d63b7dSRichard Lowe 			MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
385*10d63b7dSRichard Lowe 			plain_file_name_p = plain_file_name;
386*10d63b7dSRichard Lowe 			(void) wcscpy(plain_file_name_p, tmp_wcs_buffer);
387*10d63b7dSRichard Lowe 			plain_file = GETNAME(plain_file_name, FIND_LENGTH);
388*10d63b7dSRichard Lowe 			plain_file->stat.is_file = true;
389*10d63b7dSRichard Lowe 			plain_file->stat.has_sccs = HAS_SCCS;
390*10d63b7dSRichard Lowe 			/*
391*10d63b7dSRichard Lowe 			 * Enter the s. file as a dependency for the
392*10d63b7dSRichard Lowe 			 * plain file.
393*10d63b7dSRichard Lowe 			 */
394*10d63b7dSRichard Lowe 			maybe_append_prop(plain_file, sccs_prop)->
395*10d63b7dSRichard Lowe 			  body.sccs.file = file;
396*10d63b7dSRichard Lowe 			MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
397*10d63b7dSRichard Lowe 			if ((pattern != NULL) &&
398*10d63b7dSRichard Lowe 			    amatch(tmp_wcs_buffer, pattern)) {
399*10d63b7dSRichard Lowe 				if (debug_level > 0) {
400*10d63b7dSRichard Lowe 					WCSTOMBS(mbs_buffer, pattern);
401*10d63b7dSRichard Lowe 					(void) printf(gettext("'%s: %s' due to %s expansion\n"),
402*10d63b7dSRichard Lowe 						      line->body.line.target->
403*10d63b7dSRichard Lowe 						      string_mb,
404*10d63b7dSRichard Lowe 						      plain_file->string_mb,
405*10d63b7dSRichard Lowe 						      mbs_buffer);
406*10d63b7dSRichard Lowe 				}
407*10d63b7dSRichard Lowe 				enter_dependency(line, plain_file, false);
408*10d63b7dSRichard Lowe 				result++;
409*10d63b7dSRichard Lowe 			}
410*10d63b7dSRichard Lowe 		}
411*10d63b7dSRichard Lowe 	      }
412*10d63b7dSRichard Lowe 	}
413*10d63b7dSRichard Lowe 	(void) closedir(dir_fd);
414*10d63b7dSRichard Lowe 	if ((vpath != NULL) && (*vpath != (int) nul_char)) {
415*10d63b7dSRichard Lowe 		while ((*vpath != (int) nul_char) &&
416*10d63b7dSRichard Lowe 		       (iswspace(*vpath) || (*vpath == (int) colon_char))) {
417*10d63b7dSRichard Lowe 			vpath++;
418*10d63b7dSRichard Lowe 		}
419*10d63b7dSRichard Lowe 		p = vpath;
420*10d63b7dSRichard Lowe 		while ((*vpath != (int) colon_char) &&
421*10d63b7dSRichard Lowe 		       (*vpath != (int) nul_char)) {
422*10d63b7dSRichard Lowe 			vpath++;
423*10d63b7dSRichard Lowe 		}
424*10d63b7dSRichard Lowe 		if (vpath > p) {
425*10d63b7dSRichard Lowe 			dir = GETNAME(p, vpath - p);
426*10d63b7dSRichard Lowe 			goto vpath_loop;
427*10d63b7dSRichard Lowe 		}
428*10d63b7dSRichard Lowe 	}
429*10d63b7dSRichard Lowe /*
430*10d63b7dSRichard Lowe  * look into SCCS directory only if it's not svr4. For svr4 dont do that.
431*10d63b7dSRichard Lowe  */
432*10d63b7dSRichard Lowe 
433*10d63b7dSRichard Lowe /*
434*10d63b7dSRichard Lowe  * Now read the SCCS directory.
435*10d63b7dSRichard Lowe  * Files in the SCSC directory are considered to be part of the set of
436*10d63b7dSRichard Lowe  * files in the plain directory. They are also entered in their own right.
437*10d63b7dSRichard Lowe  * Prepare the string where we build the true name of the SCCS files.
438*10d63b7dSRichard Lowe  */
439*10d63b7dSRichard Lowe 	(void) wcsncpy(plain_file_name,
440*10d63b7dSRichard Lowe 		      file_name,
441*10d63b7dSRichard Lowe 		      file_name_p - file_name);
442*10d63b7dSRichard Lowe 	plain_file_name[file_name_p - file_name] = 0;
443*10d63b7dSRichard Lowe 	plain_file_name_p = plain_file_name + wcslen(plain_file_name);
444*10d63b7dSRichard Lowe 
445*10d63b7dSRichard Lowe         if(!svr4) {
446*10d63b7dSRichard Lowe 
447*10d63b7dSRichard Lowe 	  if (sccs_dir_path != NULL) {
448*10d63b7dSRichard Lowe 		wchar_t		tmp_wchar;
449*10d63b7dSRichard Lowe 		wchar_t		path[MAXPATHLEN];
450*10d63b7dSRichard Lowe 		char		mb_path[MAXPATHLEN];
451*10d63b7dSRichard Lowe 
452*10d63b7dSRichard Lowe 		if (file_name_p - file_name > 0) {
453*10d63b7dSRichard Lowe 			tmp_wchar = *file_name_p;
454*10d63b7dSRichard Lowe 			*file_name_p = 0;
455*10d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, file_name);
456*10d63b7dSRichard Lowe 			(void) sprintf(mb_path, "%s/%s/SCCS",
457*10d63b7dSRichard Lowe 				        sccs_dir_path,
458*10d63b7dSRichard Lowe 				        mbs_buffer);
459*10d63b7dSRichard Lowe 			*file_name_p = tmp_wchar;
460*10d63b7dSRichard Lowe 		} else {
461*10d63b7dSRichard Lowe 			(void) sprintf(mb_path, "%s/SCCS", sccs_dir_path);
462*10d63b7dSRichard Lowe 		}
463*10d63b7dSRichard Lowe 		MBSTOWCS(path, mb_path);
464*10d63b7dSRichard Lowe 		(void) wcscpy(file_name, path);
465*10d63b7dSRichard Lowe 	  } else {
466*10d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "SCCS");
467*10d63b7dSRichard Lowe 		(void) wcscpy(file_name_p, wcs_buffer);
468*10d63b7dSRichard Lowe 	  }
469*10d63b7dSRichard Lowe 	} else {
470*10d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, ".");
471*10d63b7dSRichard Lowe 		(void) wcscpy(file_name_p, wcs_buffer);
472*10d63b7dSRichard Lowe 	}
473*10d63b7dSRichard Lowe 	/* Internalize the constructed SCCS dir name. */
474*10d63b7dSRichard Lowe 	(void) exists(dir = GETNAME(file_name, FIND_LENGTH));
475*10d63b7dSRichard Lowe 	/* Just give up if the directory file doesnt exist. */
476*10d63b7dSRichard Lowe 	if (!dir->stat.is_file) {
477*10d63b7dSRichard Lowe 		return result;
478*10d63b7dSRichard Lowe 	}
479*10d63b7dSRichard Lowe 	/* Open the directory. */
480*10d63b7dSRichard Lowe 	dir_fd = opendir(dir->string_mb);
481*10d63b7dSRichard Lowe 	if (dir_fd == NULL) {
482*10d63b7dSRichard Lowe 		return result;
483*10d63b7dSRichard Lowe 	}
484*10d63b7dSRichard Lowe 	MBSTOWCS(wcs_buffer, "/");
485*10d63b7dSRichard Lowe 	(void) wcscat(file_name, wcs_buffer);
486*10d63b7dSRichard Lowe 	file_name_p = file_name + wcslen(file_name);
487*10d63b7dSRichard Lowe 
488*10d63b7dSRichard Lowe 	while ((dp = readdir(dir_fd)) != NULL) {
489*10d63b7dSRichard Lowe 		if ((dp->d_fileno == 0) ||
490*10d63b7dSRichard Lowe 		    ((dp->d_name[0] == (int) period_char) &&
491*10d63b7dSRichard Lowe 		     ((dp->d_name[1] == 0) ||
492*10d63b7dSRichard Lowe 		      ((dp->d_name[1] == (int) period_char) &&
493*10d63b7dSRichard Lowe 		       (dp->d_name[2] == 0))))) {
494*10d63b7dSRichard Lowe 			continue;
495*10d63b7dSRichard Lowe 		}
496*10d63b7dSRichard Lowe 		/* Construct and internalize the true name of the SCCS file. */
497*10d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, dp->d_name);
498*10d63b7dSRichard Lowe 		(void) wcscpy(file_name_p, wcs_buffer);
499*10d63b7dSRichard Lowe 		file = GETNAME(file_name, FIND_LENGTH);
500*10d63b7dSRichard Lowe 		file->stat.is_file = true;
501*10d63b7dSRichard Lowe 		file->stat.has_sccs = NO_SCCS;
502*10d63b7dSRichard Lowe 		/*
503*10d63b7dSRichard Lowe 		 * If this is an s. file, we also enter it as if it
504*10d63b7dSRichard Lowe 		 * existed in the plain directory.
505*10d63b7dSRichard Lowe 		 */
506*10d63b7dSRichard Lowe 		if ((dp->d_name[0] == 's') &&
507*10d63b7dSRichard Lowe 		    (dp->d_name[1] == (int) period_char)) {
508*10d63b7dSRichard Lowe 
509*10d63b7dSRichard Lowe 			MBSTOWCS(wcs_buffer, dp->d_name + 2);
510*10d63b7dSRichard Lowe 			(void) wcscpy(plain_file_name_p, wcs_buffer);
511*10d63b7dSRichard Lowe 			plain_file = GETNAME(plain_file_name, FIND_LENGTH);
512*10d63b7dSRichard Lowe 			plain_file->stat.is_file = true;
513*10d63b7dSRichard Lowe 			plain_file->stat.has_sccs = HAS_SCCS;
514*10d63b7dSRichard Lowe 				/* if sccs dependency is already set,skip */
515*10d63b7dSRichard Lowe 			if(plain_file->prop) {
516*10d63b7dSRichard Lowe 				Property sprop = get_prop(plain_file->prop,sccs_prop);
517*10d63b7dSRichard Lowe 				if(sprop != NULL) {
518*10d63b7dSRichard Lowe 					if (sprop->body.sccs.file) {
519*10d63b7dSRichard Lowe 						goto try_pattern;
520*10d63b7dSRichard Lowe 					}
521*10d63b7dSRichard Lowe 				}
522*10d63b7dSRichard Lowe 			}
523*10d63b7dSRichard Lowe 
524*10d63b7dSRichard Lowe 			/*
525*10d63b7dSRichard Lowe 			 * Enter the s. file as a dependency for the
526*10d63b7dSRichard Lowe 			 * plain file.
527*10d63b7dSRichard Lowe 			 */
528*10d63b7dSRichard Lowe 			maybe_append_prop(plain_file, sccs_prop)->
529*10d63b7dSRichard Lowe 			  body.sccs.file = file;
530*10d63b7dSRichard Lowe try_pattern:
531*10d63b7dSRichard Lowe 			MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
532*10d63b7dSRichard Lowe 			if ((pattern != NULL) &&
533*10d63b7dSRichard Lowe 			    amatch(tmp_wcs_buffer, pattern)) {
534*10d63b7dSRichard Lowe 				if (debug_level > 0) {
535*10d63b7dSRichard Lowe 					WCSTOMBS(mbs_buffer, pattern);
536*10d63b7dSRichard Lowe 					(void) printf(gettext("'%s: %s' due to %s expansion\n"),
537*10d63b7dSRichard Lowe 						      line->body.line.target->
538*10d63b7dSRichard Lowe 						      string_mb,
539*10d63b7dSRichard Lowe 						      plain_file->string_mb,
540*10d63b7dSRichard Lowe 						      mbs_buffer);
541*10d63b7dSRichard Lowe 				}
542*10d63b7dSRichard Lowe 				enter_dependency(line, plain_file, false);
543*10d63b7dSRichard Lowe 				result++;
544*10d63b7dSRichard Lowe 			}
545*10d63b7dSRichard Lowe 		}
546*10d63b7dSRichard Lowe 	}
547*10d63b7dSRichard Lowe 	(void) closedir(dir_fd);
548*10d63b7dSRichard Lowe 
549*10d63b7dSRichard Lowe 	return result;
550*10d63b7dSRichard Lowe }
551*10d63b7dSRichard Lowe 
552*10d63b7dSRichard Lowe /*
553*10d63b7dSRichard Lowe  *	enter_file_name(name_string, library)
554*10d63b7dSRichard Lowe  *
555*10d63b7dSRichard Lowe  *	Helper function for read_dir().
556*10d63b7dSRichard Lowe  *
557*10d63b7dSRichard Lowe  *	Return value:
558*10d63b7dSRichard Lowe  *				The Name that was entered
559*10d63b7dSRichard Lowe  *
560*10d63b7dSRichard Lowe  *	Parameters:
561*10d63b7dSRichard Lowe  *		name_string	Name of the file we want to enter
562*10d63b7dSRichard Lowe  *		library		The library it is a member of, if any
563*10d63b7dSRichard Lowe  *
564*10d63b7dSRichard Lowe  *	Global variables used:
565*10d63b7dSRichard Lowe  */
566*10d63b7dSRichard Lowe static Name
567*10d63b7dSRichard Lowe enter_file_name(wchar_t *name_string, wchar_t *library)
568*10d63b7dSRichard Lowe {
569*10d63b7dSRichard Lowe 	wchar_t		buffer[STRING_BUFFER_LENGTH];
570*10d63b7dSRichard Lowe 	String_rec	lib_name;
571*10d63b7dSRichard Lowe 	Name		name;
572*10d63b7dSRichard Lowe 	Property	prop;
573*10d63b7dSRichard Lowe 
574*10d63b7dSRichard Lowe 	if (library == NULL) {
575*10d63b7dSRichard Lowe 		name = GETNAME(name_string, FIND_LENGTH);
576*10d63b7dSRichard Lowe 		name->stat.is_file = true;
577*10d63b7dSRichard Lowe 		return name;
578*10d63b7dSRichard Lowe 	}
579*10d63b7dSRichard Lowe 
580*10d63b7dSRichard Lowe 	INIT_STRING_FROM_STACK(lib_name, buffer);
581*10d63b7dSRichard Lowe 	append_string(library, &lib_name, FIND_LENGTH);
582*10d63b7dSRichard Lowe 	append_char((int) parenleft_char, &lib_name);
583*10d63b7dSRichard Lowe 	append_string(name_string, &lib_name, FIND_LENGTH);
584*10d63b7dSRichard Lowe 	append_char((int) parenright_char, &lib_name);
585*10d63b7dSRichard Lowe 
586*10d63b7dSRichard Lowe 	name = GETNAME(lib_name.buffer.start, FIND_LENGTH);
587*10d63b7dSRichard Lowe 	name->stat.is_file = true;
588*10d63b7dSRichard Lowe 	name->is_member = true;
589*10d63b7dSRichard Lowe 	prop = maybe_append_prop(name, member_prop);
590*10d63b7dSRichard Lowe 	prop->body.member.library = GETNAME(library, FIND_LENGTH);
591*10d63b7dSRichard Lowe 	prop->body.member.library->stat.is_file = true;
592*10d63b7dSRichard Lowe 	prop->body.member.entry = NULL;
593*10d63b7dSRichard Lowe 	prop->body.member.member = GETNAME(name_string, FIND_LENGTH);
594*10d63b7dSRichard Lowe 	prop->body.member.member->stat.is_file = true;
595*10d63b7dSRichard Lowe 	return name;
596*10d63b7dSRichard Lowe }
597*10d63b7dSRichard Lowe 
598*10d63b7dSRichard Lowe /*
599*10d63b7dSRichard Lowe  *	star_match(string, pattern)
600*10d63b7dSRichard Lowe  *
601*10d63b7dSRichard Lowe  *	This is a regular shell type wildcard pattern matcher
602*10d63b7dSRichard Lowe  *	It is used when xpanding wildcards in dependency lists
603*10d63b7dSRichard Lowe  *
604*10d63b7dSRichard Lowe  *	Return value:
605*10d63b7dSRichard Lowe  *				Indication if the string matched the pattern
606*10d63b7dSRichard Lowe  *
607*10d63b7dSRichard Lowe  *	Parameters:
608*10d63b7dSRichard Lowe  *		string		String to match
609*10d63b7dSRichard Lowe  *		pattern		Pattern to match it against
610*10d63b7dSRichard Lowe  *
611*10d63b7dSRichard Lowe  *	Global variables used:
612*10d63b7dSRichard Lowe  */
613*10d63b7dSRichard Lowe static Boolean
614*10d63b7dSRichard Lowe star_match(register wchar_t *string, register wchar_t *pattern)
615*10d63b7dSRichard Lowe {
616*10d63b7dSRichard Lowe 	register int		pattern_ch;
617*10d63b7dSRichard Lowe 
618*10d63b7dSRichard Lowe 	switch (*pattern) {
619*10d63b7dSRichard Lowe 	case 0:
620*10d63b7dSRichard Lowe 		return succeeded;
621*10d63b7dSRichard Lowe 	case bracketleft_char:
622*10d63b7dSRichard Lowe 	case question_char:
623*10d63b7dSRichard Lowe 	case asterisk_char:
624*10d63b7dSRichard Lowe 		while (*string) {
625*10d63b7dSRichard Lowe 			if (amatch(string++, pattern)) {
626*10d63b7dSRichard Lowe 				return succeeded;
627*10d63b7dSRichard Lowe 			}
628*10d63b7dSRichard Lowe 		}
629*10d63b7dSRichard Lowe 		break;
630*10d63b7dSRichard Lowe 	default:
631*10d63b7dSRichard Lowe 		pattern_ch = (int) *pattern++;
632*10d63b7dSRichard Lowe 		while (*string) {
633*10d63b7dSRichard Lowe 			if ((*string++ == pattern_ch) &&
634*10d63b7dSRichard Lowe 			    amatch(string, pattern)) {
635*10d63b7dSRichard Lowe 				return succeeded;
636*10d63b7dSRichard Lowe 			}
637*10d63b7dSRichard Lowe 		}
638*10d63b7dSRichard Lowe 		break;
639*10d63b7dSRichard Lowe 	}
640*10d63b7dSRichard Lowe 	return failed;
641*10d63b7dSRichard Lowe }
642*10d63b7dSRichard Lowe 
643*10d63b7dSRichard Lowe /*
644*10d63b7dSRichard Lowe  *	amatch(string, pattern)
645*10d63b7dSRichard Lowe  *
646*10d63b7dSRichard Lowe  *	Helper function for shell pattern matching
647*10d63b7dSRichard Lowe  *
648*10d63b7dSRichard Lowe  *	Return value:
649*10d63b7dSRichard Lowe  *				Indication if the string matched the pattern
650*10d63b7dSRichard Lowe  *
651*10d63b7dSRichard Lowe  *	Parameters:
652*10d63b7dSRichard Lowe  *		string		String to match
653*10d63b7dSRichard Lowe  *		pattern		Pattern to match it against
654*10d63b7dSRichard Lowe  *
655*10d63b7dSRichard Lowe  *	Global variables used:
656*10d63b7dSRichard Lowe  */
657*10d63b7dSRichard Lowe static Boolean
658*10d63b7dSRichard Lowe amatch(register wchar_t *string, register wchar_t *pattern)
659*10d63b7dSRichard Lowe {
660*10d63b7dSRichard Lowe 	register long		lower_bound;
661*10d63b7dSRichard Lowe 	register long		string_ch;
662*10d63b7dSRichard Lowe 	register long		pattern_ch;
663*10d63b7dSRichard Lowe 	register int		k;
664*10d63b7dSRichard Lowe 
665*10d63b7dSRichard Lowe top:
666*10d63b7dSRichard Lowe 	for (; 1; pattern++, string++) {
667*10d63b7dSRichard Lowe 		lower_bound = 017777777777;
668*10d63b7dSRichard Lowe 		string_ch = *string;
669*10d63b7dSRichard Lowe 		switch (pattern_ch = *pattern) {
670*10d63b7dSRichard Lowe 		case bracketleft_char:
671*10d63b7dSRichard Lowe 			k = 0;
672*10d63b7dSRichard Lowe 			while ((pattern_ch = *++pattern) != 0) {
673*10d63b7dSRichard Lowe 				switch (pattern_ch) {
674*10d63b7dSRichard Lowe 				case bracketright_char:
675*10d63b7dSRichard Lowe 					if (!k) {
676*10d63b7dSRichard Lowe 						return failed;
677*10d63b7dSRichard Lowe 					}
678*10d63b7dSRichard Lowe 					string++;
679*10d63b7dSRichard Lowe 					pattern++;
680*10d63b7dSRichard Lowe 					goto top;
681*10d63b7dSRichard Lowe 				case hyphen_char:
682*10d63b7dSRichard Lowe 					k |= (lower_bound <= string_ch) &&
683*10d63b7dSRichard Lowe 					     (string_ch <=
684*10d63b7dSRichard Lowe 					      (pattern_ch = pattern[1]));
685*10d63b7dSRichard Lowe 				default:
686*10d63b7dSRichard Lowe 					if (string_ch ==
687*10d63b7dSRichard Lowe 					    (lower_bound = pattern_ch)) {
688*10d63b7dSRichard Lowe 						k++;
689*10d63b7dSRichard Lowe 					}
690*10d63b7dSRichard Lowe 				}
691*10d63b7dSRichard Lowe 			}
692*10d63b7dSRichard Lowe 			return failed;
693*10d63b7dSRichard Lowe 		case asterisk_char:
694*10d63b7dSRichard Lowe 			return star_match(string, ++pattern);
695*10d63b7dSRichard Lowe 		case 0:
696*10d63b7dSRichard Lowe 			return BOOLEAN(!string_ch);
697*10d63b7dSRichard Lowe 		case question_char:
698*10d63b7dSRichard Lowe 			if (string_ch == 0) {
699*10d63b7dSRichard Lowe 				return failed;
700*10d63b7dSRichard Lowe 			}
701*10d63b7dSRichard Lowe 			break;
702*10d63b7dSRichard Lowe 		default:
703*10d63b7dSRichard Lowe 			if (pattern_ch != string_ch) {
704*10d63b7dSRichard Lowe 				return failed;
705*10d63b7dSRichard Lowe 			}
706*10d63b7dSRichard Lowe 			break;
707*10d63b7dSRichard Lowe 		}
708*10d63b7dSRichard Lowe 	}
709*10d63b7dSRichard Lowe 	/* NOTREACHED */
710*10d63b7dSRichard Lowe }
711*10d63b7dSRichard Lowe 
712