1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)read.cc 1.64 06/12/12
29  */
30 
31 #pragma	ident	"@(#)read.cc	1.64	06/12/12"
32 
33 /*
34  * Copyright 2017-2021 J. Schilling
35  *
36  * @(#)read.cc	1.35 21/09/06 2017-2021 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)read.cc	1.35 21/09/06 2017-2021 J. Schilling";
42 #endif
43 
44 /*
45  *	read.c
46  *
47  *	This file contains the makefile reader.
48  */
49 
50 /*
51  * Included files
52  */
53 #include <avo/avo_alloca.h>		/* alloca() */
54 #include <mk/defs.h>
55 #include <mksh/macro.h>		/* expand_value(), expand_macro() */
56 #include <mksh/misc.h>		/* getmem() */
57 #include <mksh/read.h>		/* get_next_block_fn() */
58 #include <sys/uio.h>		/* read() */
59 
60 #if defined(TEAMWARE_MAKE_CMN)
61 #if defined(HP_UX) || defined(linux)
62 #include <avo/types.h>
63 extern "C" Avo_err *avo_find_run_dir(char **dirp);
64 #endif
65 #endif
66 
67 #include <schily/stdio.h>
68 #include <schily/wchar.h>
69 #include <schily/schily.h>
70 
71 /*
72  * We cannot use "using std::wcsdup" as wcsdup() is not always
73  * in the std namespace.
74  * The Sun CC compiler in version 4 does not suport using namespace std;
75  * so be careful.
76  */
77 #if !defined(__SUNPRO_CC_COMPAT) || __SUNPRO_CC_COMPAT >= 5
78 using namespace std;		/* needed for wcsdup() */
79 #endif
80 
81 /*
82  * typedefs & structs
83  */
84 
85 enum directive {
86 	D_NONE = 0,		/* No valid directive found	*/
87 	D_INCLUDE,		/* "include" directive found	*/
88 	D_IINCLUDE,		/* "-include" directive found	*/
89 	D_EXPORT,		/* "export" directive found	*/
90 	D_UNEXPORT,		/* "unexport" directive found	*/
91 	D_READONLY		/* "readonly" directive found	*/
92 };
93 
94 /*
95  * Static variables
96  */
97 
98 static int line_started_with_space=0; // Used to diagnose spaces instead of tabs
99 
100 /*
101  * Make sure that there is space for the null byte after the string.
102  */
103 static wchar_t		include_d[8+1];
104 static wchar_t		iinclude_d[9+1];
105 static wchar_t		export_d[7+1];
106 static wchar_t		unexport_d[9+1];
107 static wchar_t		readonly_d[9+1];
108 
109 static struct dent {
110 	wchar_t		*directive;
111 	int		dlen;
112 	enum directive	dir;
113 } directives[] = {
114 	{ include_d,	7, D_INCLUDE },
115 	{ iinclude_d,	8, D_IINCLUDE },
116 	{ export_d,	6, D_EXPORT },
117 	{ unexport_d,	8, D_UNEXPORT },
118 	{ readonly_d,	8, D_READONLY },
119 	{ NULL,		0, D_NONE }
120 };
121 
122 /*
123  * File table of contents
124  */
125 static	void		parse_makefile(register Name true_makefile_name, register Source source);
126 static	Source		push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source);
127 extern  void 		enter_target_groups_and_dependencies(Name_vector target, Name_vector depes, Cmd_line command, Separator separator, Boolean target_group_seen);
128 extern	Name		normalize_name(register wchar_t *name_string, register int length);
129 extern	void		doexport(Name name);
130 extern	void		dounexport(Name name);
131 extern	void		doreadonly(Name name);
132 
133 static Boolean		skip_comment(wchar_t * &source_p, wchar_t * &source_end, Source &source);
134 static void		init_directives(void);
135 
136 /*
137  *	read_simple_file(makefile_name, chase_path, doname_it,
138  *		 complain, must_exist, report_file, lock_makefile)
139  *
140  *	Make the makefile and setup to read it. Actually read it if it is stdio
141  *
142  *	Return value:
143  *				false if the read failed
144  *
145  *	Parameters:
146  *		makefile_name	Name of the file to read
147  *		chase_path	Use the makefile path when opening file
148  *		doname_it	Call doname() to build the file first
149  *		complain	Print message if doname/open fails
150  *		must_exist	Generate fatal if file is missing
151  *		report_file	Report file when running -P
152  *		lock_makefile	Lock the makefile when reading
153  *
154  *	Static variables used:
155  *
156  *	Global variables used:
157  *		do_not_exec_rule Is -n on?
158  *		file_being_read	Set to the name of the new file
159  *		line_number	The number of the current makefile line
160  *		makefiles_used	A list of all makefiles used, appended to
161  */
162 
163 
164 Boolean
read_simple_file(register Name makefile_name,register Boolean chase_path,register Boolean doname_it,Boolean complain,Boolean must_exist,Boolean report_file,Boolean lock_makefile,Boolean is_include)165 read_simple_file(register Name makefile_name, register Boolean chase_path, register Boolean doname_it, Boolean complain, Boolean must_exist, Boolean report_file, Boolean lock_makefile, Boolean is_include)
166 {
167 	static short		max_include_depth;
168 	register Property	makefile = maybe_append_prop(makefile_name,
169 							     makefile_prop);
170 	Boolean			forget_after_parse = false;
171 	static pathpt		makefile_path;
172 	register int		n;
173 	char			*path;
174 	register Source		source = ALLOC(Source);
175 	Property		orig_makefile = makefile;
176 	Dependency		*dpp;
177 	Dependency		dp;
178 	register int		length;
179 	wchar_t			*previous_file_being_read = file_being_read;
180 	int			previous_line_number = line_number;
181 	wchar_t			previous_current_makefile[MAXPATHLEN];
182 	Makefile_type		save_makefile_type;
183 	Name 			normalized_makefile_name;
184 	register wchar_t        *string_start;
185 	register wchar_t        *string_end;
186 	char                    *run_dir, makerules_dir[BUFSIZ];
187 
188 
189 #if defined(TEAMWARE_MAKE_CMN)
190 #if defined(HP_UX) || defined(linux)
191 	Avo_err                 *findrundir_err;
192 #endif
193 #endif
194 
195 	wchar_t * wcb = get_wstring(makefile_name->string_mb);
196 
197 #ifdef NSE
198 	if (report_file){
199 		wcscpy(previous_current_makefile, current_makefile);
200 		wcscpy(current_makefile, wcb);
201 	}
202 #endif
203 	if (max_include_depth++ >= 40) {
204 		fatal(gettext("Too many nested include statements"));
205 	}
206 	if (makefile->body.makefile.contents != NULL) {
207 		retmem(makefile->body.makefile.contents);
208 	}
209 	source->inp_buf =
210 	  source->inp_buf_ptr =
211 	    source->inp_buf_end = NULL;
212 	source->error_converting = false;
213 	makefile->body.makefile.contents = NULL;
214 	makefile->body.makefile.size = 0;
215 	if ((makefile_name->hash.length != 1) ||
216 	    (wcb[0] != (int) hyphen_char)) {
217 		if ((makefile->body.makefile.contents == NULL) &&
218 		    (doname_it)) {
219 			if (makefile_path == NULL) {
220 				add_dir_to_path(".",
221 						&makefile_path,
222 						-1);
223 #if !defined(TEAMWARE_MAKE_CMN)
224                 		run_dir = make_run_dir;
225 				if (run_dir) {
226 					if (strstr(run_dir, "xpg4/bin") ||
227 					    strstr(run_dir, "/onbld/")) {
228 	                        		(void) sprintf(makerules_dir,
229 						NOCATGETS("%s/../../share/lib/make"), run_dir);
230 					} else {
231 	                        		(void) sprintf(makerules_dir,
232 						NOCATGETS("%s/../share/lib/make"), run_dir);
233 					}
234 					add_dir_to_path(makerules_dir,
235 							&makefile_path,
236 							-1);
237 				}
238 #ifdef INS_BASE
239 				add_dir_to_path(NOCATGETS(INS_BASE "/share/lib/make"),
240 						&makefile_path,
241 						-1);
242 #endif
243 				add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
244 						&makefile_path,
245 						-1);
246 				add_dir_to_path(NOCATGETS("/etc/default"),
247 						&makefile_path,
248 						-1);
249 #else
250 #ifdef SUN5_0
251 				add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
252 						&makefile_path,
253 						-1);
254 				add_dir_to_path(NOCATGETS("/etc/default"),
255 						&makefile_path,
256 						-1);
257 #elif defined(HP_UX)
258                 		findrundir_err = avo_find_run_dir(&run_dir);
259                 		if (! findrundir_err) {
260                         		(void) sprintf(makerules_dir, NOCATGETS("%s/../share/lib/make"), run_dir);
261 					add_dir_to_path(makerules_dir,
262 							&makefile_path,
263 							-1);
264                 		}
265 
266 				add_dir_to_path(NOCATGETS("/opt/SUNWspro/share/lib/make"),
267 						&makefile_path,
268 						-1);
269 				add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
270 						&makefile_path,
271 						-1);
272 #elif defined(linux)
273                 		findrundir_err = avo_find_run_dir(&run_dir);
274                 		if (! findrundir_err) {
275                         		(void) sprintf(makerules_dir, NOCATGETS("%s/../lib"), run_dir);
276 					add_dir_to_path(makerules_dir,
277 							&makefile_path,
278 							-1);
279                 		}
280 
281 				add_dir_to_path(NOCATGETS("/usr/SUNWspro/lib"),
282 						&makefile_path,
283 						-1);
284 				add_dir_to_path(NOCATGETS("/opt/SUNWspro/share/lib/make"),
285 						&makefile_path,
286 						-1);
287 				add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
288 						&makefile_path,
289 						-1);
290 #else
291 				add_dir_to_path(NOCATGETS("/usr/include/make"),
292 						&makefile_path,
293 						-1);
294 #endif
295 #endif
296 			}
297 			save_makefile_type = makefile_type;
298 			makefile_type = reading_nothing;
299 			if (doname(makefile_name, true, false) == build_dont_know) {
300 				/* Try normalized filename */
301 				string_start=get_wstring(makefile_name->string_mb);
302 				for (string_end=string_start+1; *string_end != '\0'; string_end++);
303 				normalized_makefile_name=normalize_name(string_start, string_end - string_start);
304 				if ((strcmp(makefile_name->string_mb, normalized_makefile_name->string_mb) == 0) ||
305 					(doname(normalized_makefile_name, true, false) == build_dont_know)) {
306 					n = access_vroot(makefile_name->string_mb,
307 						 4,
308 						 chase_path ?
309 						 makefile_path : NULL,
310 						 VROOT_DEFAULT);
311 					if (n == 0) {
312 						get_vroot_path((char **) NULL,
313 						       &path,
314 						       (char **) NULL);
315 						if ((path[0] == (int) period_char) &&
316 						    (path[1] == (int) slash_char)) {
317 							path += 2;
318 						}
319 						MBSTOWCS(wcs_buffer, path);
320 						makefile_name = GETNAME(wcs_buffer,
321 								FIND_LENGTH);
322 					}
323 				}
324 				retmem(string_start);
325 				/*
326 				 * Commented out: retmem_mb(normalized_makefile_name->string_mb);
327 				 * We have to return this memory, but it seems to trigger a bug
328 				 * in dmake or in Sun C++ 5.7 compiler (it works ok if this code
329 				 * is compiled using Sun C++ 5.6).
330 				 */
331 				// retmem_mb(normalized_makefile_name->string_mb);
332 			}
333 			makefile_type = save_makefile_type;
334 		}
335 		source->string.free_after_use = false;
336 		source->previous = NULL;
337 		source->already_expanded = false;
338 		/* Lock the file for read, but not when -n. */
339 		if (lock_makefile &&
340 		    !do_not_exec_rule) {
341 
342 			 make_state_lockfile = getmem(strlen(make_state->string_mb) + strlen(NOCATGETS(".lock")) + 1);
343 			 (void) sprintf(make_state_lockfile,
344 						NOCATGETS("%s.lock"),
345 						make_state->string_mb);
346 			(void) file_lock(make_state->string_mb,
347 					 make_state_lockfile,
348 					 (int *) &make_state_locked,
349 					 0);
350 			if(!make_state_locked) {
351 				printf(NOCATGETS("-- NO LOCKING for read\n"));
352 				retmem_mb(make_state_lockfile);
353 				make_state_lockfile = 0;
354 				return failed;
355 			}
356 		}
357 		if (makefile->body.makefile.contents == NULL) {
358 			save_makefile_type = makefile_type;
359 			makefile_type = reading_nothing;
360 			if ((doname_it) &&
361 			    (doname(makefile_name, true, false) == build_failed)) {
362 				if (complain) {
363 					(void) fprintf(stderr,
364 #ifdef DISTRIBUTED
365 						       gettext("dmake: Couldn't dmake `%s'\n"),
366 #else
367 						       gettext("make: Couldn't make `%s'\n"),
368 #endif
369 						       makefile_name->string_mb);
370 				}
371 				max_include_depth--;
372 				makefile_type = save_makefile_type;
373 				return failed;
374 			}
375 			makefile_type = save_makefile_type;
376 			//
377 			// Before calling exists() make sure that we have the right timestamp
378 			//
379 			makefile_name->stat.time = file_no_time;
380 #ifdef	DO_INCLUDE_FAILED
381 			/*
382 			 * Only call rule commands for "include", not for
383 			 * "-include". This is the case if "complain" is true.
384 			 */
385 			if (is_include && complain && include_failed &&
386 			    exists(makefile_name) == file_doesnt_exist) {
387 				register Property	line;
388 
389 				if ((line = get_prop(include_failed_name->prop, line_prop)) != NULL &&
390 				    line->body.line.command_template) {
391 					struct _Dependency	dep;
392 
393 					dep.next = NULL;
394 					dep.name = makefile_name;
395 					dep.automatic = dep.stale = dep.built = false;
396 					line->body.line.dependencies = &dep;	/* Set up $^ */
397 					makefile_name->stat.time = file_max_time;
398 					doname(include_failed_name, false, false);
399 					line->body.line.dependencies = NULL;
400 					makefile_name->stat.time = file_no_time;
401 				}
402 			}
403 #endif
404 
405 			if (exists(makefile_name) == file_doesnt_exist) {
406 				if (complain ||
407 				    (makefile_name->stat.stat_errno != ENOENT)) {
408 					if (must_exist) {
409 						fatal(gettext("Can't find `%s': %s"),
410 						      makefile_name->string_mb,
411 						      errmsg(makefile_name->
412 							     stat.stat_errno));
413 					} else {
414 						warning(gettext("Can't find `%s': %s"),
415 							makefile_name->string_mb,
416 							errmsg(makefile_name->
417 							       stat.stat_errno));
418 					}
419 				}
420 				max_include_depth--;
421 				if(make_state_locked && (make_state_lockfile != NULL)) {
422 					(void) unlink(make_state_lockfile);
423 					retmem_mb(make_state_lockfile);
424 					make_state_lockfile = NULL;
425 					make_state_locked = false;
426 				}
427 				retmem(wcb);
428 				retmem_mb((char *)source);
429 				return failed;
430 			}
431 			/*
432 			 * These values are the size and bytes of
433 			 * the MULTI-BYTE makefile.
434 			 */
435 			orig_makefile->body.makefile.size =
436 			  makefile->body.makefile.size =
437 			    source->bytes_left_in_file =
438 			      makefile_name->stat.size;
439 			if (report_file) {
440 				for (dpp = &makefiles_used;
441 				     *dpp != NULL;
442 				     dpp = &(*dpp)->next);
443 				dp = ALLOC(Dependency);
444 				dp->next = NULL;
445 				dp->name = makefile_name;
446 				dp->automatic = false;
447 				dp->stale = false;
448 				dp->built = false;
449 				*dpp = dp;
450 			}
451 			source->fd = open_vroot(makefile_name->string_mb,
452 						O_RDONLY,
453 						0,
454 						NULL,
455 						VROOT_DEFAULT);
456 			if (source->fd < 0) {
457 				if (complain || (errno != ENOENT)) {
458 					if (must_exist) {
459 						fatal(gettext("Can't open `%s': %s"),
460 						      makefile_name->string_mb,
461 						      errmsg(errno));
462 					} else {
463 						warning(gettext("Can't open `%s': %s"),
464 							makefile_name->string_mb,
465 							errmsg(errno));
466 					}
467 				}
468 				max_include_depth--;
469 				return failed;
470 			}
471 			(void) fcntl(source->fd, F_SETFD, 1);
472 			orig_makefile->body.makefile.contents =
473 			  makefile->body.makefile.contents =
474 			    source->string.text.p =
475 			      source->string.buffer.start =
476 				ALLOC_WC((int) (makefile_name->stat.size + 2));
477 			if (makefile_type == reading_cpp_file) {
478 				forget_after_parse = true;
479 			}
480 			source->string.text.end = source->string.text.p;
481 			source->string.buffer.end =
482 			  source->string.text.p + makefile_name->stat.size;
483 		} else {
484 			/* Do we ever reach here? */
485 			source->fd = -1;
486 			source->string.text.p =
487 			  source->string.buffer.start =
488 			    makefile->body.makefile.contents;
489 			source->string.text.end =
490 			  source->string.buffer.end =
491 			    source->string.text.p + makefile->body.makefile.size;
492 			source->bytes_left_in_file =
493 			  makefile->body.makefile.size;
494 		}
495 		file_being_read = wcb;
496 	} else {
497 		char		*stdin_text_p;
498 		char		*stdin_text_end;
499 		char		*stdin_buffer_start;
500 		char		*stdin_buffer_end;
501 		char		*p_mb;
502 		int		num_mb_chars;
503 		size_t		num_wc_chars;
504 
505 		MBSTOWCS(wcs_buffer, NOCATGETS("Standard in"));
506 		makefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
507 		/*
508 		 * Memory to read standard in, then convert it
509 		 * to wide char strings.
510 		 */
511 		stdin_buffer_start =
512 		  stdin_text_p = getmem(length = 1024);
513 		stdin_buffer_end = stdin_text_p + length;
514 		MBSTOWCS(wcs_buffer, NOCATGETS("standard input"));
515 		file_being_read = (wchar_t *) wcsdup(wcs_buffer);
516 		line_number = 0;
517 		while ((n = read(fileno(stdin),
518 				 stdin_text_p,
519 				 length)) > 0) {
520 			length -= n;
521 			stdin_text_p += n;
522 			if (length == 0) {
523 				p_mb = getmem(length = 1024 +
524 					      (stdin_buffer_end -
525 					       stdin_buffer_start));
526 				(void) strncpy(p_mb,
527 					       stdin_buffer_start,
528 					       (stdin_buffer_end -
529 					        stdin_buffer_start));
530 				retmem_mb(stdin_buffer_start);
531 				stdin_text_p = p_mb +
532 				  (stdin_buffer_end - stdin_buffer_start);
533 				stdin_buffer_start = p_mb;
534 				stdin_buffer_end =
535 				  stdin_buffer_start + length;
536 				length = 1024;
537 			}
538 		}
539 		if (n < 0) {
540 			fatal(gettext("Error reading standard input: %s"),
541 			      errmsg(errno));
542 		}
543 		stdin_text_p = stdin_buffer_start;
544 		stdin_text_end = stdin_buffer_end - length;
545 		num_mb_chars = stdin_text_end - stdin_text_p;
546 
547 		/*
548 		 * Now, convert the sequence of multibyte chars into
549 		 * a sequence of corresponding wide character codes.
550 		 */
551 		source->string.free_after_use = false;
552 		source->previous = NULL;
553 		source->bytes_left_in_file = 0;
554 		source->fd = -1;
555 		source->already_expanded = false;
556 		source->string.buffer.start =
557 		  source->string.text.p = ALLOC_WC(num_mb_chars + 1);
558 		source->string.buffer.end =
559 		    source->string.text.p + num_mb_chars;
560 		num_wc_chars = mbstowcs(source->string.text.p,
561 					stdin_text_p,
562 					num_mb_chars);
563 		if ((int) num_wc_chars >= 0) {
564 			source->string.text.end =
565 			  source->string.text.p + num_wc_chars;
566 		}
567 		(void) retmem_mb(stdin_text_p);
568 	}
569 	line_number = 1;
570 	if (trace_reader) {
571 		(void) printf(gettext(">>>>>>>>>>>>>>>> Reading makefile %s\n"),
572 			      makefile_name->string_mb);
573 	}
574 	parse_makefile(makefile_name, source);
575 	if (trace_reader) {
576 		(void) printf(gettext(">>>>>>>>>>>>>>>> End of makefile %s\n"),
577 			      makefile_name->string_mb);
578 	}
579 #ifdef NSE
580 	if (report_file && (previous_current_makefile[0] != NULL)) {
581 		wcscpy(current_makefile, previous_current_makefile);
582 	}
583 #endif
584 	if(file_being_read) {
585 		retmem(file_being_read);
586 	}
587 	file_being_read = previous_file_being_read;
588 	line_number = previous_line_number;
589 	makefile_type = reading_nothing;
590 	max_include_depth--;
591 	if (make_state_locked) {
592 		/* Unlock .make.state. */
593 		unlink(make_state_lockfile);
594 		make_state_locked = false;
595 		retmem_mb(make_state_lockfile);
596 	}
597 	if (forget_after_parse) {
598 		retmem(makefile->body.makefile.contents);
599 		makefile->body.makefile.contents = NULL;
600 	}
601 	retmem_mb((char *)source);
602 	return succeeded;
603 }
604 
605 /*
606  *	parse_makefile(true_makefile_name, source)
607  *
608  *	Strings are read from Sources.
609  *	When macros are found, their values are represented by a
610  *	Source that is pushed on a stack. At end of string
611  *	(that is returned from GET_CHAR() as 0), the block is popped.
612  *
613  *	Parameters:
614  *		true_makefile_name	The name of makefile we are parsing
615  *		source			The source block to read from
616  *
617  *	Global variables used:
618  *		do_not_exec_rule Is -n on?
619  *		line_number	The number of the current makefile line
620  *		makefile_type	What kind of makefile are we reading?
621  *		empty_name	The Name ""
622  */
623 static void
parse_makefile(register Name true_makefile_name,register Source source)624 parse_makefile(register Name true_makefile_name, register Source source)
625 {
626 /*
627 	char			mb_buffer[MB_LEN_MAX];
628  */
629 	register wchar_t	*source_p;
630 	register wchar_t	*source_end;
631 	register wchar_t	*string_start;
632 	wchar_t			*string_end;
633 	register Boolean	macro_seen_in_string;
634 	Boolean			append;
635 	Boolean			expand;
636 	String_rec		name_string;
637 	wchar_t			name_buffer[STRING_BUFFER_LENGTH];
638 	register int		distance;
639 	register int		paren_count;
640 	int			brace_count;
641 	int			char_number;
642 	Cmd_line		command;
643 	Cmd_line		command_tail;
644 	Name			macro_value;
645 
646 	Name_vector_rec		target;
647 	Name_vector_rec		depes;
648 	Name_vector_rec		extra_name_vector;
649 	Name_vector		current_names;
650 	Name_vector		extra_names = &extra_name_vector;
651 	Name_vector		nvp;
652 	Boolean			target_group_seen;
653 
654 	register Reader_state   state;
655 	register Reader_state   on_eoln_state;
656 	register Separator	separator;
657 
658 	wchar_t                 buffer[4 * STRING_BUFFER_LENGTH];
659 	Source			extrap;
660 
661 	Boolean                 save_do_not_exec_rule = do_not_exec_rule;
662 	Name                    makefile_name;
663 	Name                    makefile_name_raw;
664 
665 	static Name		sh_name;
666 	static Name		shell_name;
667 	int			i;
668 
669 	int			tmp_bytes_left_in_string;
670 	Boolean			tmp_maybe_directive = false;
671 	int    			emptycount = 0;
672 	Boolean			first_target;
673 
674 	enum directive		directive_type;
675 	int			directive_len;
676 	struct dent		*dp;
677 
678 	String_rec		include_name;
679 	wchar_t			include_buffer[STRING_BUFFER_LENGTH];
680 
681 	target.next = depes.next = NULL;
682 	/* Move some values from their struct to register declared locals */
683 	CACHE_SOURCE(0);
684 
685  start_new_line:
686 	/*
687 	 * Read whitespace on old line. Leave pointer on first char on
688 	 * next line.
689 	 */
690 	first_target = true;
691 	on_eoln_state = exit_state;
692 /*
693 	for (WCTOMB(mb_buffer, GET_CHAR());
694 	     1;
695 	     source_p++, WCTOMB(mb_buffer, GET_CHAR()))
696 		switch (mb_buffer[0]) {
697  */
698 	for (char_number=0; 1; source_p++,char_number++) switch (GET_CHAR()) {
699 	case nul_char:
700 		/* End of this string. Pop it and return to the previous one */
701 		GET_NEXT_BLOCK(source);
702 		source_p--;
703 		if (source == NULL) {
704 			GOTO_STATE(on_eoln_state);
705 		}
706 		break;
707 	case newline_char:
708 	end_of_line:
709 		source_p++;
710 		if (source->fd >= 0) {
711 			line_number++;
712 		}
713 		switch (GET_CHAR()) {
714 		case nul_char:
715 			GET_NEXT_BLOCK(source);
716 			if (source == NULL) {
717 				GOTO_STATE(on_eoln_state);
718 			}
719 			/* Go back to the top of this loop */
720 			goto start_new_line;
721 		case newline_char:
722 		case numbersign_char:
723 		case dollar_char:
724 		case space_char:
725 		case tab_char:
726 			/*
727 			 * Go back to the top of this loop since the
728 			 * new line does not start with a regular char.
729 			 */
730 			goto start_new_line;
731 		default:
732 			/* We found the first proper char on the new line */
733 			goto start_new_line_no_skip;
734 		}
735 	case space_char:
736 		if (char_number == 0)
737 			line_started_with_space=line_number;
738 	case tab_char:
739 		/* Whitespace. Just keep going in this loop */
740 		break;
741 	case numbersign_char:
742 		/* Comment. Skip over it */
743 		if (skip_comment(source_p, source_end, source) == false) {
744 			GOTO_STATE(on_eoln_state);
745 		}
746 		/*
747 		 * After we skip the comment we go to
748 		 * the end of line handler since end of
749 		 * line terminates comments.
750 		 */
751 		goto end_of_line;
752 	case dollar_char:
753 		/* Macro reference */
754 		if (source->already_expanded) {
755 			/*
756 			 * If we are reading from the expansion of a
757 			 * macro we already expanded everything enough.
758 			 */
759 			goto start_new_line_no_skip;
760 		}
761 		/*
762 		 * Expand the value and push the Source on the stack of
763 		 * things being read.
764 		 */
765 		source_p++;
766 		UNCACHE_SOURCE();
767 		{
768 			Source t = (Source) alloca((int) sizeof (Source_rec));
769 			source = push_macro_value(t,
770 						  buffer,
771 						  sizeof buffer,
772 						  source);
773 		}
774 		CACHE_SOURCE(1);
775 		break;
776 	default:
777 		/* We found the first proper char on the new line */
778 		goto start_new_line_no_skip;
779 	}
780 
781 	/*
782 	 * We found the first normal char (one that starts an identifier)
783 	 * on the newline.
784 	 */
785 start_new_line_no_skip:
786 	/* Inspect that first char to see if it maybe is special anyway */
787 	switch (GET_CHAR()) {
788 	case nul_char:
789 		GET_NEXT_BLOCK(source);
790 		if (source == NULL) {
791 			GOTO_STATE(on_eoln_state);
792 		}
793 		goto start_new_line_no_skip;
794 	case newline_char:
795 		/* Just in case */
796 		goto start_new_line;
797 	case exclam_char:
798 		/* Evaluate the line before it is read */
799 		string_start = source_p + 1;
800 		macro_seen_in_string = false;
801 		/* Stuff the line in a string so we can eval it. */
802 		for (; 1; source_p++) {
803 			switch (GET_CHAR()) {
804 			case newline_char:
805 				goto eoln_1;
806 			case nul_char:
807 				if (source->fd > 0) {
808 					if (!macro_seen_in_string) {
809 						macro_seen_in_string = true;
810 						INIT_STRING_FROM_STACK(
811 						      name_string, name_buffer);
812 					}
813 					append_string(string_start,
814 						      &name_string,
815 						      source_p - string_start);
816 					GET_NEXT_BLOCK(source);
817 					string_start = source_p;
818 					source_p--;
819 					break;
820 				}
821 			eoln_1:
822 				if (!macro_seen_in_string) {
823 					INIT_STRING_FROM_STACK(name_string,
824 							       name_buffer);
825 				}
826 				append_string(string_start,
827 					      &name_string,
828 					      source_p - string_start);
829 				extrap = (Source)
830 				  alloca((int) sizeof (Source_rec));
831 				extrap->string.buffer.start = NULL;
832 				extrap->inp_buf =
833 				  extrap->inp_buf_ptr =
834 				    extrap->inp_buf_end = NULL;
835 				extrap->error_converting = false;
836 				if (*source_p == (int) nul_char) {
837 					source_p++;
838 				}
839 				/* Eval the macro */
840 				expand_value(GETNAME(name_string.buffer.start,
841 						     FIND_LENGTH),
842 					     &extrap->string,
843 					     false);
844 				if (name_string.free_after_use) {
845 					retmem(name_string.buffer.start);
846 				}
847 				UNCACHE_SOURCE();
848 				extrap->string.text.p =
849 				  extrap->string.buffer.start;
850 				extrap->fd = -1;
851 				/* And push the value */
852 				extrap->previous = source;
853 				source = extrap;
854 				CACHE_SOURCE(0);
855 				goto line_evald;
856 			}
857 		}
858 	default:
859 		goto line_evald;
860 	}
861 
862 	/* We now have a line we can start reading */
863  line_evald:
864 	if (source == NULL) {
865 		GOTO_STATE(exit_state);
866 	}
867 	/* Check if this is a directive command */
868 	if ((makefile_type == reading_makefile) &&
869 	    !source->already_expanded) {
870 
871 	    if (include_d[0] == (int) nul_char)
872 		init_directives();
873 
874 	    directive_len = 0;
875 	    directive_type = D_NONE;
876 	    for (dp = directives; dp->directive; dp++) {
877 		if (IS_WEQUALN(source_p, dp->directive, dp->dlen)) {
878 			if (source_p[dp->dlen] == (int)space_char ||
879 			    source_p[dp->dlen] == (int)tab_char) {
880 				directive_len = dp->dlen;
881 				directive_type = dp->dir;
882 				break;
883 			}
884 		}
885 		if (sunpro_compat)
886 			break;
887 	    }
888 
889 	    if (directive_type) {
890 		source_p += directive_len;
891 	try_next_include:	/* More than one include name on the line? */
892 
893 		if (!sunpro_compat && *source_p == numbersign_char)
894 			goto start_new_line;
895 		if (iswspace(*source_p)) {
896 			Makefile_type save_makefile_type;
897 			wchar_t		*name_start;
898 			int		name_length;
899 			String_rec	destination;
900 
901 			/*
902 			 * Yes, this is an include.
903 			 * Skip spaces to get to the filename.
904 			 */
905 			while (iswspace(*source_p) ||
906 			       (*source_p == (int) nul_char)) {
907 				switch (GET_CHAR()) {
908 				case newline_char:
909 					goto start_new_line;
910 
911 				case nul_char:
912 					GET_NEXT_BLOCK(source);
913 					if (source == NULL) {
914 						GOTO_STATE(on_eoln_state);
915 					}
916 					break;
917 
918 				default:
919 					source_p++;
920 					break;
921 				}
922 			}
923 
924 			string_start = source_p;
925 			/* Find the end of the filename */
926 			macro_seen_in_string = false;
927 			while (!iswspace(*source_p) ||
928 			       (*source_p == (int) nul_char)) {
929 				switch (GET_CHAR()) {
930 				case nul_char:
931 					if (!macro_seen_in_string) {
932 						INIT_STRING_FROM_STACK(name_string,
933 								       name_buffer);
934 					}
935 					append_string(string_start,
936 						      &name_string,
937 						      source_p - string_start);
938 					macro_seen_in_string = true;
939 					GET_NEXT_BLOCK(source);
940 					string_start = source_p;
941 					if (source == NULL) {
942 						GOTO_STATE(on_eoln_state);
943 					}
944 					break;
945 
946 			    	case numbersign_char:
947 					if (!sunpro_compat) {
948 						if (source_p == string_start)
949 							goto start_new_line;
950 						goto string_end;
951 					}
952 
953 				default:
954 					source_p++;
955 					break;
956 				}
957 			}
958 
959 	string_end:
960 			source->string.text.p = source_p;
961 			if (macro_seen_in_string) {
962 				append_string(string_start,
963 					      &name_string,
964 					      source_p - string_start);
965 				name_start = name_string.buffer.start;
966 				name_length = name_string.text.p - name_start;
967 			} else {
968 				name_start = string_start;
969 				name_length = source_p - string_start;
970 			}
971 
972 			/* Strip "./" from the head of the name */
973 			if ((name_start[0] == (int) period_char) &&
974 	    		   (name_start[1] == (int) slash_char)) {
975 				name_start += 2;
976 				name_length -= 2;
977 			}
978 			/* if include file name is surrounded by double quotes */
979 			if ((name_start[0] == (int) doublequote_char) &&
980 			    (name_start[name_length - 1] == (int) doublequote_char)) {
981 			    	name_start += 1;
982 			    	name_length -= 2;
983 
984 			    	/* if name does not begin with a slash char */
985 			    	if (name_start[0] != (int) slash_char) {
986 					if ((name_start[0] == (int) period_char) &&
987 					    (name_start[1] == (int) slash_char)) {
988 						name_start += 2;
989 						name_length -= 2;
990 					}
991 
992 					INIT_STRING_FROM_STACK(include_name, include_buffer);
993 					APPEND_NAME(true_makefile_name,
994 						      &include_name,
995 						      true_makefile_name->hash.length);
996 
997 					wchar_t *slash = wcsrchr(include_name.buffer.start, (int) slash_char);
998 					if (slash != NULL) {
999 						include_name.text.p = slash + 1;
1000 						append_string(name_start,
1001 							      &include_name,
1002 							      name_length);
1003 
1004 						name_start = include_name.buffer.start;
1005 						name_length = include_name.text.p - name_start;
1006 					}
1007 				}
1008 			}
1009 
1010 			/* Even when we run -n we want to create makefiles */
1011 			do_not_exec_rule = false;
1012 			makefile_name_raw = GETNAME(name_start, name_length);
1013 			if (makefile_name_raw->dollar) {
1014 				wchar_t		buffer[STRING_BUFFER_LENGTH];
1015 				wchar_t		*p;
1016 				wchar_t		*q;
1017 
1018 				INIT_STRING_FROM_STACK(destination, buffer);
1019 				expand_value(makefile_name_raw,
1020 					     &destination,
1021 					     false);
1022 
1023 				destination.text.p = destination.buffer.start;
1024 			next_in_var:
1025 				for (p = destination.text.p;
1026 				     (*p != (int) nul_char) && iswspace(*p);
1027 				     p++);
1028 				for (q = p;
1029 				     (*q != (int) nul_char) && !iswspace(*q);
1030 				     q++);
1031 				destination.text.p = q;
1032 
1033 				makefile_name = GETNAME(p, q-p);
1034 				if (destination.text.p >= destination.text.end &&
1035 				    destination.free_after_use) {
1036 					/*
1037 					 * Free it after we did a complete
1038 					 * parsing of the macro value.
1039 					 */
1040 					retmem(destination.buffer.start);
1041 				}
1042 			} else {
1043 				makefile_name = makefile_name_raw;
1044 			}
1045 			switch (directive_type) {
1046 
1047 			case D_INCLUDE:
1048 			case D_IINCLUDE:
1049 				UNCACHE_SOURCE();
1050 				/* Read the file */
1051 				save_makefile_type = makefile_type;
1052 				/*
1053 				 * The original make program from Sun did complain with:
1054 				 * FOO=
1055 				 * include $(FOO)
1056 				 * but this is in conflict with the behavior of smake
1057 				 * and gmake and it would cause prolems if we allow
1058 				 * $(FOO) to expand to more than one incude file name.
1059 				 * So let us be quiet with empty includes.
1060 				 */
1061 				if (*makefile_name->string_mb != nul_char &&
1062 				    read_simple_file(makefile_name,
1063 					     true,
1064 					     true,
1065 					     directive_type == D_IINCLUDE ? false:true,
1066 					     false,
1067 					     true,
1068 					     false,
1069 					     true) == failed && directive_type != D_IINCLUDE) {
1070 					fatal_reader(gettext("Read of include file `%s' failed"),
1071 					     makefile_name->string_mb);
1072 				}
1073 				makefile_type = save_makefile_type;
1074 				do_not_exec_rule = save_do_not_exec_rule;
1075 				CACHE_SOURCE(0);
1076 				break;
1077 
1078 			case D_EXPORT:
1079 				doexport(makefile_name);
1080 				break;
1081 			case D_UNEXPORT:
1082 				dounexport(makefile_name);
1083 				break;
1084 			case D_READONLY:
1085 				doreadonly(makefile_name);
1086 				break;
1087 			case D_NONE:
1088 				/*
1089 				 * Since we checked for directive_type != 0
1090 				 * before, this cannot happen, but it makes
1091 				 * clang quiet.
1092 				 */
1093 				break;
1094 			}
1095 			if (sunpro_compat) {
1096 				source_p++;
1097 				goto start_new_line;
1098 			}
1099 			if (makefile_name != makefile_name_raw) {
1100 				/*
1101 				 * The "makefile_name" is not from a line in
1102 				 * Makefile, but from a macro expansion. Check
1103 				 * whether there may be more names in the value
1104 				 * of that macro.
1105 				 */
1106 				if (destination.text.p < destination.text.end)
1107 					goto next_in_var;
1108 			}
1109 			if (*source_p != newline_char) {
1110 				/*
1111 				 * The next character after the filename in the
1112 				 * include directive was not a newline, there
1113 				 * may be more names in that directive line.
1114 				 */
1115 				goto try_next_include;
1116 			}
1117 			source_p++;
1118 			goto start_new_line;
1119 		} else {
1120 			source_p -= directive_len;
1121 		}
1122 	    } else {
1123 		/* Check if the directive text was split across 8K boundary. */
1124 
1125 		tmp_bytes_left_in_string = source->string.text.end - source_p;
1126 		if (tmp_bytes_left_in_string < 9) {
1127 			struct dent	*dp;
1128 
1129 			tmp_maybe_directive = false;
1130 			for (dp = directives; dp->directive; dp++) {
1131 				if (dp != directives && sunpro_compat)
1132 					break;
1133 				if (dp->dlen < tmp_bytes_left_in_string)
1134 					continue;
1135 				if (IS_WEQUALN(source_p, dp->directive,
1136 				    dp->dlen)) {
1137 					tmp_maybe_directive = true;
1138 					break;
1139 				}
1140 			}
1141 			if (tmp_maybe_directive) {
1142 				GET_NEXT_BLOCK(source);
1143 				tmp_maybe_directive = false;
1144 				goto line_evald;
1145 			}
1146 		}
1147 	    }
1148 	}
1149 
1150 	/* Reset the status in preparation for the new line */
1151 	for (nvp = &target; nvp != NULL; nvp = nvp->next) {
1152 		nvp->used = 0;
1153 	}
1154 	for (nvp = &depes; nvp != NULL; nvp = nvp->next) {
1155 		nvp->used = 0;
1156 	}
1157 	target_group_seen = false;
1158 	command = command_tail = NULL;
1159 	macro_value = NULL;
1160 	append = false;
1161 	expand = false;
1162 	current_names = &target;
1163 	SET_STATE(scan_name_state);
1164 	on_eoln_state = illegal_eoln_state;
1165 	separator = none_seen;
1166 
1167 	/* The state machine starts here */
1168  enter_state:
1169 	while (1) switch (state) {
1170 
1171 /****************************************************************
1172  *	Scan name state
1173  */
1174 case scan_name_state:
1175 	/* Scan an identifier. We skip over chars until we find a break char */
1176 	/* First skip white space. */
1177 	for (; 1; source_p++) switch (GET_CHAR()) {
1178 	case nul_char:
1179 		GET_NEXT_BLOCK(source);
1180 		source_p--;
1181 		if (source == NULL) {
1182 			GOTO_STATE(on_eoln_state);
1183 		}
1184 		break;
1185 	case newline_char:
1186 		/* We found the end of the line. */
1187 		/* Do postprocessing or return error */
1188 		source_p++;
1189 		if (source->fd >= 0) {
1190 			line_number++;
1191 		}
1192 		GOTO_STATE(on_eoln_state);
1193 	case backslash_char:
1194 		/* Continuation */
1195 		if (*++source_p == (int) nul_char) {
1196 			GET_NEXT_BLOCK(source);
1197 			if (source == NULL) {
1198 				GOTO_STATE(on_eoln_state);
1199 			}
1200 		}
1201 		if (*source_p == (int) newline_char) {
1202 			if (source->fd >= 0) {
1203 				line_number++;
1204 			}
1205 		} else {
1206 			source_p--;
1207 		}
1208 		break;
1209 	case tab_char:
1210 	case space_char:
1211 		/* Whitespace is skipped */
1212 		break;
1213 	case numbersign_char:
1214 		/* Comment. Skip over it */
1215 		if (skip_comment(source_p, source_end, source) == true) {
1216 			source_p++;
1217 			if (source->fd >= 0) {
1218 				line_number++;
1219 			}
1220 		}
1221 		GOTO_STATE(on_eoln_state);
1222 	case dollar_char:
1223 		/* Macro reference. Expand and push value */
1224 		if (source->already_expanded) {
1225 			goto scan_name;
1226 		}
1227 		source_p++;
1228 		UNCACHE_SOURCE();
1229 		{
1230 			Source t = (Source) alloca((int) sizeof (Source_rec));
1231 			source = push_macro_value(t,
1232 						  buffer,
1233 						  sizeof buffer,
1234 						  source);
1235 		}
1236 		CACHE_SOURCE(1);
1237 		break;
1238 	default:
1239 		/* End of white space */
1240 		goto scan_name;
1241 	}
1242 
1243 	/* First proper identifier character */
1244  scan_name:
1245 
1246 	string_start = source_p;
1247 	paren_count = brace_count = 0;
1248 	macro_seen_in_string = false;
1249 	resume_name_scan:
1250 	for (; 1; source_p++) {
1251 		switch (GET_CHAR()) {
1252 		case nul_char:
1253 			/* Save what we have seen so far of the identifier */
1254 			if (source_p != string_start) {
1255 				if (!macro_seen_in_string) {
1256 					INIT_STRING_FROM_STACK(name_string,
1257 							       name_buffer);
1258 				}
1259 				append_string(string_start,
1260 					      &name_string,
1261 					      source_p - string_start);
1262 				macro_seen_in_string = true;
1263 			}
1264 			/* Get more text to read */
1265 			GET_NEXT_BLOCK(source);
1266 			string_start = source_p;
1267 			source_p--;
1268 			if (source == NULL) {
1269 				GOTO_STATE(on_eoln_state);
1270 			}
1271 			break;
1272 		case newline_char:
1273 			if (paren_count > 0) {
1274 				fatal_reader(gettext("Unmatched `(' on line"));
1275 			}
1276 			if (brace_count > 0) {
1277 				fatal_reader(gettext("Unmatched `{' on line"));
1278 			}
1279 			source_p++;
1280 			/* Enter name */
1281 			current_names = enter_name(&name_string,
1282 						   macro_seen_in_string,
1283 						   string_start,
1284 						   source_p - 1,
1285 						   current_names,
1286 						   &extra_names,
1287 						   &target_group_seen);
1288 			first_target = false;
1289 			if (extra_names == NULL) {
1290 				extra_names = (Name_vector)
1291 				  alloca((int) sizeof (Name_vector_rec));
1292 			}
1293 			/* Do postprocessing or return error */
1294 			if (source->fd >= 0) {
1295 				line_number++;
1296 			}
1297 			GOTO_STATE(on_eoln_state);
1298 		case backslash_char:
1299 			/* Check if this is a quoting backslash */
1300 			if (!macro_seen_in_string) {
1301 				INIT_STRING_FROM_STACK(name_string,
1302 						       name_buffer);
1303 				macro_seen_in_string = true;
1304 			}
1305 			append_string(string_start,
1306 				      &name_string,
1307 				      source_p - string_start);
1308 			if (*++source_p == (int) nul_char) {
1309 				GET_NEXT_BLOCK(source);
1310 				if (source == NULL) {
1311 					GOTO_STATE(on_eoln_state);
1312 				}
1313 			}
1314 			if (*source_p == (int) newline_char) {
1315 				if (source->fd >= 0) {
1316 					line_number++;
1317 				}
1318 				*source_p = (int) space_char;
1319 				string_start = source_p;
1320 				goto resume_name_scan;
1321 			} else {
1322 				string_start = source_p;
1323 				break;
1324 			}
1325 			break;
1326 		case numbersign_char:
1327 			if (paren_count + brace_count > 0) {
1328 				break;
1329 			}
1330 			fatal_reader(gettext("Unexpected comment seen"));
1331 		case dollar_char:
1332 			if (source->already_expanded) {
1333 				break;
1334 			}
1335 			/* Save the identifier so far */
1336 			if (source_p != string_start) {
1337 				if (!macro_seen_in_string) {
1338 					INIT_STRING_FROM_STACK(name_string,
1339 							       name_buffer);
1340 				}
1341 				append_string(string_start,
1342 					      &name_string,
1343 					      source_p - string_start);
1344 				macro_seen_in_string = true;
1345 			}
1346 			/* Eval and push the macro */
1347 			source_p++;
1348 			UNCACHE_SOURCE();
1349 			{
1350 				Source t =
1351 				  (Source) alloca((int) sizeof (Source_rec));
1352 				source = push_macro_value(t,
1353 							  buffer,
1354 							  sizeof buffer,
1355 							  source);
1356 			}
1357 			CACHE_SOURCE(1);
1358 			string_start = source_p + 1;
1359 			break;
1360 		case parenleft_char:
1361 			paren_count++;
1362 			break;
1363 		case parenright_char:
1364 			if (--paren_count < 0) {
1365 				fatal_reader(gettext("Unmatched `)' on line"));
1366 			}
1367 			break;
1368 		case braceleft_char:
1369 			brace_count++;
1370 			break;
1371 		case braceright_char:
1372 			if (--brace_count < 0) {
1373 				fatal_reader(gettext("Unmatched `}' on line"));
1374 			}
1375 			break;
1376 		case ampersand_char:
1377 		case greater_char:
1378 		case bar_char:
1379 			if (paren_count + brace_count == 0) {
1380 				source_p++;
1381 			}
1382 			/* Fall into */
1383 		case tab_char:
1384 		case space_char:
1385 			if (paren_count + brace_count > 0) {
1386 				break;
1387 			}
1388 			current_names = enter_name(&name_string,
1389 						   macro_seen_in_string,
1390 						   string_start,
1391 						   source_p,
1392 						   current_names,
1393 						   &extra_names,
1394 						   &target_group_seen);
1395 			first_target = false;
1396 			if (extra_names == NULL) {
1397 				extra_names = (Name_vector)
1398 				  alloca((int) sizeof (Name_vector_rec));
1399 			}
1400 			goto enter_state;
1401 		case colon_char:
1402 			if (paren_count + brace_count > 0) {
1403 				break;
1404 			}
1405 			if (separator == conditional_seen) {
1406 				break;
1407 			}
1408 /** POSIX **/
1409 #if 0
1410 			if(posix) {
1411 			  emptycount = 0;
1412 			}
1413 #endif
1414 /** END POSIX **/
1415 			/* End of the target list. We now start reading */
1416 			/* dependencies or a conditional assignment */
1417 			if (separator != none_seen &&
1418 			    ((sunpro_compat || svr4) ||
1419 			    (separator != two_colon))) {
1420 				fatal_reader(gettext("Extra `:', `::', or `:=' on dependency line"));
1421 			}
1422 			/* Enter the last target */
1423 			if ((string_start != source_p) ||
1424 			    macro_seen_in_string) {
1425 				current_names =
1426 				  enter_name(&name_string,
1427 					     macro_seen_in_string,
1428 					     string_start,
1429 					     source_p,
1430 					     current_names,
1431 					     &extra_names,
1432 					     &target_group_seen);
1433 				first_target = false;
1434 				if (extra_names == NULL) {
1435 					extra_names = (Name_vector)
1436 					  alloca((int)
1437 						 sizeof (Name_vector_rec));
1438 				}
1439 			}
1440 			/* Check if it is ":" "::" or ":=" */
1441 		scan_colon_label:
1442 			switch (*++source_p) {
1443 			case nul_char:
1444 				GET_NEXT_BLOCK(source);
1445 				source_p--;
1446 				if (source == NULL) {
1447 					GOTO_STATE(enter_dependencies_state);
1448 				}
1449 				goto scan_colon_label;
1450 			case equal_char:
1451 				if(svr4) {
1452 				  fatal_reader(gettext("syntax error"));
1453 				}
1454 				if (separator == two_colon) {
1455 					separator = three_colon;
1456 					break;
1457 				}
1458 				separator = conditional_seen;
1459 				source_p++;
1460 				current_names = &depes;
1461 				GOTO_STATE(scan_name_state);
1462 			case colon_char:
1463 				separator = two_colon;
1464 				source_p++;
1465 				break;
1466 			default:
1467 				separator = one_colon;
1468 			}
1469 			current_names = &depes;
1470 			on_eoln_state = enter_dependencies_state;
1471 			GOTO_STATE(scan_name_state);
1472 		case semicolon_char:
1473 			if (paren_count + brace_count > 0) {
1474 				break;
1475 			}
1476 			/* End of reading names. Start reading the rule */
1477 			if ((separator != one_colon) &&
1478 			    (separator != two_colon)) {
1479 				fatal_reader(gettext("Unexpected command seen"));
1480 			}
1481 			/* Enter the last dependency */
1482 			if ((string_start != source_p) ||
1483 			    macro_seen_in_string) {
1484 				current_names =
1485 				  enter_name(&name_string,
1486 					     macro_seen_in_string,
1487 					     string_start,
1488 					     source_p,
1489 					     current_names,
1490 					     &extra_names,
1491 					     &target_group_seen);
1492 				first_target = false;
1493 				if (extra_names == NULL) {
1494 					extra_names = (Name_vector)
1495 					  alloca((int)
1496 						 sizeof (Name_vector_rec));
1497 				}
1498 			}
1499 			source_p++;
1500 			/* Make sure to enter a rule even if the is */
1501 			/* no text here */
1502 			command = command_tail = ALLOC(Cmd_line);
1503 			command->next = NULL;
1504 			command->command_line = empty_name;
1505 			command->make_refd = false;
1506 			command->ignore_command_dependency = false;
1507 			command->assign = false;
1508 			command->ignore_error = false;
1509 			command->silent = false;
1510 
1511 			GOTO_STATE(scan_command_state);
1512 
1513 		case question_char:
1514 			if (sunpro_compat || svr4)
1515 				break;
1516 			if (source_p != string_start) {
1517 				/* "?" is not a break char. */
1518 				/* Ignore it if it is part of an identifier */
1519 				source_p++;
1520 				goto resume_name_scan;
1521 			}
1522 			/* Make sure the "?" is followed by a "=" */
1523 		scan_quest_label:
1524 			switch (source_p[1]) {
1525 			case nul_char:
1526 				GET_NEXT_BLOCK(source);
1527 				string_start = source_p;
1528 				if (source == NULL) {
1529 					GOTO_STATE(on_eoln_state);
1530 				}
1531 				goto scan_quest_label;
1532 
1533 			case equal_char:
1534 				separator = one_quest;
1535 				string_start = ++source_p;
1536 				goto scan_equal;
1537 			}
1538 			break;
1539 
1540 		case plus_char:
1541 			/*
1542 			** following code drops the target separator plus char if it starts
1543 			** a line.
1544 			*/
1545 			if(first_target && !macro_seen_in_string &&
1546 					source_p == string_start) {
1547 				for (; 1; source_p++)
1548 				switch (GET_CHAR()) {
1549 				case nul_char:
1550 					if (source_p != string_start) {
1551 						if (!macro_seen_in_string) {
1552 							INIT_STRING_FROM_STACK(name_string,
1553 									       name_buffer);
1554 						}
1555 						append_string(string_start,
1556 							      &name_string,
1557 							      source_p - string_start);
1558 						macro_seen_in_string = true;
1559 					}
1560 					GET_NEXT_BLOCK(source);
1561 					string_start = source_p;
1562 					source_p--;
1563 					if (source == NULL) {
1564 						GOTO_STATE(on_eoln_state);
1565 					}
1566 					break;
1567 				case plus_char:
1568 					source_p++;
1569 					while (*source_p == (int) nul_char) {
1570 						if (source_p != string_start) {
1571 							if (!macro_seen_in_string) {
1572 								INIT_STRING_FROM_STACK(name_string,
1573 									       name_buffer);
1574 							}
1575 							append_string(string_start,
1576 								      &name_string,
1577 								      source_p - string_start);
1578 							macro_seen_in_string = true;
1579 						}
1580 						GET_NEXT_BLOCK(source);
1581 						string_start = source_p;
1582 						if (source == NULL) {
1583 							GOTO_STATE(on_eoln_state);
1584 						}
1585 					}
1586 					if (*source_p == (int) tab_char ||
1587 							*source_p == (int) space_char) {
1588 						macro_seen_in_string = false;
1589 						string_start = source_p + 1;
1590 					} else {
1591 						goto resume_name_scan;
1592 					}
1593 					break;
1594 				case tab_char:
1595 				case space_char:
1596 					string_start = source_p + 1;
1597 					break;
1598 				default:
1599 					goto resume_name_scan;
1600 				}
1601 			}
1602 			if (paren_count + brace_count > 0) {
1603 				break;
1604 			}
1605 			/* We found "+=" construct */
1606 			if (source_p != string_start) {
1607 				/* "+" is not a break char. */
1608 				/* Ignore it if it is part of an identifier */
1609 				source_p++;
1610 				goto resume_name_scan;
1611 			}
1612 			/*
1613 			 * Make sure the "+" is followed by a "="
1614 			 * or by a ":="
1615 			 */
1616 		scan_append:
1617 			switch (*++source_p) {
1618 			case nul_char:
1619 			wasnull:
1620 				if (!macro_seen_in_string) {
1621 					INIT_STRING_FROM_STACK(name_string,
1622 							       name_buffer);
1623 				}
1624 				append_string(string_start,
1625 					      &name_string,
1626 					      source_p - string_start);
1627 				GET_NEXT_BLOCK(source);
1628 				source_p--;
1629 				string_start = source_p;
1630 				if (source == NULL) {
1631 					GOTO_STATE(illegal_eoln_state);
1632 				}
1633 				goto scan_append;
1634 			case colon_char:	/* This might be +:= */
1635 				if (source_p[1] == nul_char)
1636 					goto wasnull;
1637 				if ((sunpro_compat || svr4) ||
1638 				    source_p[1] != equal_char) {
1639 					goto resume_name_scan;
1640 				}
1641 				source_p++;	/* skip ':' from +:= */
1642 				expand = true;
1643 			case equal_char:
1644 				if(!svr4) {
1645 				  append = true;
1646 				} else {
1647 				  fatal_reader(gettext("Must be a separator on rules"));
1648 				}
1649 				break;
1650 			default:
1651 				/* The "+" just starts a regular name. */
1652 				/* Start reading that name */
1653 				goto resume_name_scan;
1654 			}
1655 			/* Fall into */
1656 		case equal_char:
1657 		scan_equal:
1658 			if (paren_count + brace_count > 0) {
1659 				break;
1660 			}
1661 			/* We found macro assignment. */
1662 			/* Check if it is legal and if it is appending */
1663 			switch (separator) {
1664 			case none_seen:
1665 				separator = equal_seen;
1666 				on_eoln_state = enter_equal_state;
1667 				break;
1668 			case conditional_seen:
1669 				on_eoln_state = enter_conditional_state;
1670 				break;
1671 			case one_quest:
1672 				if (!sunpro_compat && !svr4) {
1673 					separator = condequal_seen;
1674 					on_eoln_state = enter_equal_state;
1675 					break;
1676 				}
1677 			case two_colon:
1678 				if (separator == two_colon) /* fallthrough? */
1679 #ifdef	GNU_ASSIGN_BY_DEFAULT
1680 				if (
1681 #else
1682 				if ((posix || gnu_style) &&
1683 #endif
1684 				    !sunpro_compat && !svr4) {
1685 					separator = gnu_assign_seen;
1686 					on_eoln_state = enter_equal_state;
1687 					break;
1688 				}
1689 			case three_colon:
1690 				if (separator == three_colon) /* fallthrough? */
1691 				if (!sunpro_compat && !svr4) {
1692 					separator = assign_seen;
1693 					on_eoln_state = enter_equal_state;
1694 					break;
1695 				}
1696 			default:
1697 				/* Reader must special check for "MACRO:sh=" */
1698 				/* notation */
1699 				if (sh_name == NULL) {
1700 					MBSTOWCS(wcs_buffer, NOCATGETS("sh"));
1701 					sh_name = GETNAME(wcs_buffer, FIND_LENGTH);
1702 					MBSTOWCS(wcs_buffer, NOCATGETS("shell"));
1703 					shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
1704 				}
1705 
1706 				if (!macro_seen_in_string) {
1707 					INIT_STRING_FROM_STACK(name_string,
1708 						       name_buffer);
1709 				}
1710 				append_string(string_start,
1711 					      &name_string,
1712 					      source_p - string_start
1713 				);
1714 
1715 				if ( (((target.used == 1) &&
1716 				     (depes.used == 1) &&
1717 				     (depes.names[0] == sh_name)) ||
1718 				    ((target.used == 1) &&
1719 				     (depes.used == 0) &&
1720 				     (separator == one_colon) &&
1721 				     (GETNAME(name_string.buffer.start,FIND_LENGTH) == sh_name))) &&
1722 				    (!svr4)) {
1723 					String_rec	macro_name;
1724 					wchar_t		buffer[100];
1725 
1726 					INIT_STRING_FROM_STACK(macro_name,
1727 							       buffer);
1728 					APPEND_NAME(target.names[0],
1729 						      &macro_name,
1730 						      FIND_LENGTH);
1731 					append_char((int) colon_char,
1732 						    &macro_name);
1733 					APPEND_NAME(sh_name,
1734 						      &macro_name,
1735 						      FIND_LENGTH);
1736 					target.names[0] =
1737 					  GETNAME(macro_name.buffer.start,
1738 						  FIND_LENGTH);
1739 					separator = equal_seen;
1740 					on_eoln_state = enter_equal_state;
1741 					break;
1742 				} else if ( (((target.used == 1) &&
1743 					    (depes.used == 1) &&
1744 					    (depes.names[0] == shell_name)) ||
1745 					   ((target.used == 1) &&
1746 					    (depes.used == 0) &&
1747 					    (separator == one_colon) &&
1748 					    (GETNAME(name_string.buffer.start,FIND_LENGTH) == shell_name))) &&
1749 					   (!svr4)) {
1750 					String_rec	macro_name;
1751 					wchar_t		buffer[100];
1752 
1753 					INIT_STRING_FROM_STACK(macro_name,
1754 							       buffer);
1755 					APPEND_NAME(target.names[0],
1756 						      &macro_name,
1757 						      FIND_LENGTH);
1758 					append_char((int) colon_char,
1759 						    &macro_name);
1760 					APPEND_NAME(shell_name,
1761 						      &macro_name,
1762 						      FIND_LENGTH);
1763 					target.names[0] =
1764 					  GETNAME(macro_name.buffer.start,
1765 						  FIND_LENGTH);
1766 					separator = equal_seen;
1767 					on_eoln_state = enter_equal_state;
1768 					break;
1769 				}
1770 				if(svr4) {
1771 				  fatal_reader(gettext("syntax error"));
1772 				}
1773 				else {
1774 				  fatal_reader(gettext("Macro assignment on dependency line"));
1775 				}
1776 			}
1777 			if (append) {
1778 				source_p--;
1779 				if (*source_p == colon_char)
1780 					source_p--;
1781 			}
1782 			/* Enter the macro name */
1783 			if ((string_start != source_p) ||
1784 			    macro_seen_in_string) {
1785 				current_names =
1786 				  enter_name(&name_string,
1787 					     macro_seen_in_string,
1788 					     string_start,
1789 					     source_p,
1790 					     current_names,
1791 					     &extra_names,
1792 					     &target_group_seen);
1793 				first_target = false;
1794 				if (extra_names == NULL) {
1795 					extra_names = (Name_vector)
1796 					  alloca((int)
1797 						 sizeof (Name_vector_rec));
1798 				}
1799 			}
1800 			if (append) {
1801 				source_p++;
1802 				if (*source_p == colon_char)
1803 					source_p++;
1804 			}
1805 			macro_value = NULL;
1806 			source_p++;
1807 			distance = 0;
1808 			/* Skip whitespace to the start of the value */
1809 			macro_seen_in_string = false;
1810 			for (; 1; source_p++) {
1811 				switch (GET_CHAR()) {
1812 				case nul_char:
1813 					GET_NEXT_BLOCK(source);
1814 					source_p--;
1815 					if (source == NULL) {
1816 						GOTO_STATE(on_eoln_state);
1817 					}
1818 					break;
1819 				case backslash_char:
1820 					if (*++source_p == (int) nul_char) {
1821 						GET_NEXT_BLOCK(source);
1822 						if (source == NULL) {
1823 							GOTO_STATE(on_eoln_state);
1824 						}
1825 					}
1826 					if (*source_p != (int) newline_char) {
1827 						if (!macro_seen_in_string) {
1828 							macro_seen_in_string =
1829 							  true;
1830 							INIT_STRING_FROM_STACK(name_string,
1831 									       name_buffer);
1832 						}
1833 						append_char((int)
1834 							    backslash_char,
1835 							    &name_string);
1836 						append_char(*source_p,
1837 							    &name_string);
1838 						string_start = source_p+1;
1839 						goto macro_value_start;
1840 					} else {
1841                                             if (source->fd >= 0) {
1842                                             	line_number++;
1843                                             }
1844                                         }
1845 					break;
1846 				case newline_char:
1847 				case numbersign_char:
1848 					string_start = source_p;
1849 					goto macro_value_end;
1850 				case tab_char:
1851 				case space_char:
1852 					break;
1853 				default:
1854 					string_start = source_p;
1855 					goto macro_value_start;
1856 				}
1857 			}
1858 		macro_value_start:
1859 			/* Find the end of the value */
1860 			for (; 1; source_p++) {
1861 				if (distance != 0) {
1862 					*source_p = *(source_p + distance);
1863 				}
1864 				switch (GET_CHAR()) {
1865 				case nul_char:
1866 					if (!macro_seen_in_string) {
1867 						macro_seen_in_string = true;
1868 						INIT_STRING_FROM_STACK(name_string,
1869 								       name_buffer);
1870 					}
1871 					append_string(string_start,
1872 						      &name_string,
1873 						      source_p - string_start);
1874 					GET_NEXT_BLOCK(source);
1875 					string_start = source_p;
1876 					source_p--;
1877 					if (source == NULL) {
1878 						GOTO_STATE(on_eoln_state);
1879 					}
1880 					break;
1881 				case backslash_char:
1882 					source_p++;
1883 					if (distance != 0) {
1884 						*source_p =
1885 						  *(source_p + distance);
1886 					}
1887 					if (*source_p == (int) nul_char) {
1888 						if (!macro_seen_in_string) {
1889 							macro_seen_in_string =
1890 							  true;
1891 							INIT_STRING_FROM_STACK(name_string,
1892 									       name_buffer);
1893 						}
1894 
1895 /*  BID_1225561 */
1896 						*(source_p - 1) = (int) space_char;
1897 						append_string(string_start,
1898 							      &name_string,
1899 							      source_p -
1900 							      string_start - 1);
1901 						GET_NEXT_BLOCK(source);
1902 						string_start = source_p;
1903 						if (source == NULL) {
1904 							GOTO_STATE(on_eoln_state);
1905 						}
1906 						if (distance != 0) {
1907 							*source_p =
1908 							  *(source_p +
1909 							    distance);
1910 						}
1911 						if (*source_p == (int) newline_char) {
1912 							append_char((int) space_char, &name_string);
1913 						} else {
1914 							append_char((int) backslash_char, &name_string);
1915 						}
1916 /****************/
1917 					}
1918 					if (*source_p == (int) newline_char) {
1919 						source_p--;
1920 						line_number++;
1921 						distance++;
1922 						*source_p = (int) space_char;
1923 						while ((*(source_p +
1924 							  distance + 1) ==
1925 							(int) tab_char) ||
1926 						       (*(source_p +
1927 							  distance + 1) ==
1928 							(int) space_char)) {
1929 							distance++;
1930 						}
1931 					}
1932 					break;
1933 				case newline_char:
1934 				case numbersign_char:
1935 					goto macro_value_end;
1936 				}
1937 			}
1938 		macro_value_end:
1939 			/* Complete the value in the string */
1940 			if (!macro_seen_in_string) {
1941 				macro_seen_in_string = true;
1942 				INIT_STRING_FROM_STACK(name_string,
1943 						       name_buffer);
1944 			}
1945 			append_string(string_start,
1946 				      &name_string,
1947 				      source_p - string_start);
1948 			if (name_string.buffer.start != name_string.text.p) {
1949 					macro_value =
1950 					  GETNAME(name_string.buffer.start,
1951 						  FIND_LENGTH);
1952 				}
1953 			if (name_string.free_after_use) {
1954 				retmem(name_string.buffer.start);
1955 			}
1956 			for (; distance > 0; distance--) {
1957 				*source_p++ = (int) space_char;
1958 			}
1959 			GOTO_STATE(on_eoln_state);
1960 		}
1961 	}
1962 
1963 /****************************************************************
1964  *	enter dependencies state
1965  */
1966  case enter_dependencies_state:
1967  enter_dependencies_label:
1968 /* Expects pointer on first non whitespace char after last dependency. (On */
1969 /* next line.) We end up here after having read a "targets : dependencies" */
1970 /* line. The state checks if there is a rule to read and if so dispatches */
1971 /* to scan_command_state scan_command_state reads one rule line and the */
1972 /* returns here */
1973 
1974 	/* First check if the first char on the next line is special */
1975 	switch (GET_CHAR()) {
1976 	case nul_char:
1977 		GET_NEXT_BLOCK(source);
1978 		if (source == NULL) {
1979 			break;
1980 		}
1981 		goto enter_dependencies_label;
1982 	case exclam_char:
1983 		/* The line should be evaluate before it is read */
1984 		macro_seen_in_string = false;
1985 		string_start = source_p + 1;
1986 		for (; 1; source_p++) {
1987 			switch (GET_CHAR()) {
1988 			case newline_char:
1989 				goto eoln_2;
1990 			case nul_char:
1991 				if (source->fd > 0) {
1992 					if (!macro_seen_in_string) {
1993 						macro_seen_in_string = true;
1994 						INIT_STRING_FROM_STACK(name_string,
1995 								       name_buffer);
1996 					}
1997 					append_string(string_start,
1998 						      &name_string,
1999 						      source_p - string_start);
2000 					GET_NEXT_BLOCK(source);
2001 					string_start = source_p;
2002 					source_p--;
2003 					break;
2004 				}
2005 			eoln_2:
2006 				if (!macro_seen_in_string) {
2007 					INIT_STRING_FROM_STACK(name_string,
2008 							       name_buffer);
2009 				}
2010 				append_string(string_start,
2011 					      &name_string,
2012 					      source_p - string_start);
2013 				extrap = (Source)
2014 				  alloca((int) sizeof (Source_rec));
2015 				extrap->string.buffer.start = NULL;
2016 				extrap->inp_buf =
2017 				  extrap->inp_buf_ptr =
2018 				    extrap->inp_buf_end = NULL;
2019 				extrap->error_converting = false;
2020 				expand_value(GETNAME(name_string.buffer.start,
2021 						     FIND_LENGTH),
2022 					     &extrap->string,
2023 					     false);
2024 				if (name_string.free_after_use) {
2025 					retmem(name_string.buffer.start);
2026 				}
2027 				UNCACHE_SOURCE();
2028 				extrap->string.text.p =
2029 				  extrap->string.buffer.start;
2030 				extrap->fd = -1;
2031 				extrap->previous = source;
2032 				source = extrap;
2033 				CACHE_SOURCE(0);
2034 				goto enter_dependencies_label;
2035 			}
2036 		}
2037 	case dollar_char:
2038 		if (source->already_expanded) {
2039 			break;
2040 		}
2041 		source_p++;
2042 		UNCACHE_SOURCE();
2043 		{
2044 			Source t = (Source) alloca((int) sizeof (Source_rec));
2045 			source = push_macro_value(t,
2046 						  buffer,
2047 						  sizeof buffer,
2048 						  source);
2049 		}
2050 		CACHE_SOURCE(0);
2051 		goto enter_dependencies_label;
2052 	case numbersign_char:
2053 		if (makefile_type != reading_makefile) {
2054 			source_p++;
2055 			GOTO_STATE(scan_command_state);
2056 		}
2057 		for (; 1; source_p++) {
2058 			switch (GET_CHAR()) {
2059 			case nul_char:
2060 				GET_NEXT_BLOCK_NOCHK(source);
2061 				if (source == NULL) {
2062 					GOTO_STATE(on_eoln_state);
2063 				}
2064 				if (source->error_converting) {
2065 				// Illegal byte sequence - skip its first byte
2066 					source->inp_buf_ptr++;
2067 				}
2068 				source_p--;
2069 				break;
2070 			case backslash_char:
2071 				if (*++source_p == (int) nul_char) {
2072 					GET_NEXT_BLOCK_NOCHK(source);
2073 					if (source == NULL) {
2074 						GOTO_STATE(on_eoln_state);
2075 					}
2076 					if (source->error_converting) {
2077 					// Illegal byte sequence - skip its first byte
2078 						source->inp_buf_ptr++;
2079 						source_p--;
2080 						break;
2081 					}
2082 				}
2083 				if(*source_p == (int) newline_char) {
2084 					if (source->fd >= 0) {
2085 						line_number++;
2086 					}
2087 				}
2088 				break;
2089 			case newline_char:
2090 				source_p++;
2091 				if (source->fd >= 0) {
2092 					line_number++;
2093 				}
2094 				goto enter_dependencies_label;
2095 			}
2096 		}
2097 
2098 	case tab_char:
2099 		GOTO_STATE(scan_command_state);
2100 	}
2101 
2102 	/* We read all the command lines for the target/dependency line. */
2103 	/* Enter the stuff */
2104 	enter_target_groups_and_dependencies( &target, &depes, command,
2105 					     separator, target_group_seen);
2106 
2107 	goto start_new_line;
2108 
2109 /****************************************************************
2110  *	scan command state
2111  */
2112 case scan_command_state:
2113 	/* We need to read one rule line. Do that and return to */
2114 	/* the enter dependencies state */
2115 	string_start = source_p;
2116 	macro_seen_in_string = false;
2117 	for (; 1; source_p++) {
2118 		switch (GET_CHAR()) {
2119 		case backslash_char:
2120 			if (!macro_seen_in_string) {
2121 				INIT_STRING_FROM_STACK(name_string,
2122 						       name_buffer);
2123 			}
2124 			append_string(string_start,
2125 				      &name_string,
2126 				      source_p - string_start);
2127 			macro_seen_in_string = true;
2128 			if (*++source_p == (int) nul_char) {
2129 				GET_NEXT_BLOCK(source);
2130 				if (source == NULL) {
2131 					string_start = source_p;
2132 					goto command_newline;
2133 				}
2134 			}
2135 			append_char((int) backslash_char, &name_string);
2136 			append_char(*source_p, &name_string);
2137 			if (*source_p == (int) newline_char) {
2138 				if (source->fd >= 0) {
2139 					line_number++;
2140 				}
2141 				if (*++source_p == (int) nul_char) {
2142 					GET_NEXT_BLOCK(source);
2143 					if (source == NULL) {
2144 						string_start = source_p;
2145 						goto command_newline;
2146 					}
2147 				}
2148 				if (*source_p == (int) tab_char) {
2149 					source_p++;
2150 				}
2151 			} else {
2152 				if (*++source_p == (int) nul_char) {
2153 					GET_NEXT_BLOCK(source);
2154 					if (source == NULL) {
2155 						string_start = source_p;
2156 						goto command_newline;
2157 					}
2158 				}
2159 			}
2160 			string_start = source_p;
2161 			if ((*source_p == (int) newline_char) ||
2162 			    (*source_p == (int) backslash_char) ||
2163 			    (*source_p == (int) nul_char)) {
2164 				source_p--;
2165 			}
2166 			break;
2167 		case newline_char:
2168 		command_newline:
2169 			if ((string_start != source_p) ||
2170 			    macro_seen_in_string) {
2171 				if (macro_seen_in_string) {
2172 					append_string(string_start,
2173 						      &name_string,
2174 						      source_p - string_start);
2175 					string_start =
2176 					  name_string.buffer.start;
2177 					string_end = name_string.text.p;
2178 				} else {
2179 					string_end = source_p;
2180 				}
2181 				while ((*string_start != (int) newline_char) &&
2182 				       iswspace(*string_start)){
2183 					string_start++;
2184 				}
2185 				if ((string_end > string_start) ||
2186 				    (makefile_type == reading_statefile)) {
2187 					if (command_tail == NULL) {
2188 						command =
2189 						  command_tail =
2190 						    ALLOC(Cmd_line);
2191 					} else {
2192 						command_tail->next =
2193 						  ALLOC(Cmd_line);
2194 						command_tail =
2195 						  command_tail->next;
2196 					}
2197 					command_tail->next = NULL;
2198 					command_tail->make_refd = false;
2199 					command_tail->ignore_command_dependency = false;
2200 					command_tail->assign = false;
2201 					command_tail->ignore_error = false;
2202 					command_tail->silent = false;
2203 					command_tail->command_line =
2204 					  GETNAME(string_start,
2205 						  string_end - string_start);
2206 					if (macro_seen_in_string &&
2207 					    name_string.free_after_use) {
2208 						retmem(name_string.
2209 						       buffer.start);
2210 					}
2211 				}
2212 			}
2213 			do {
2214 				if ((source != NULL) && (source->fd >= 0)) {
2215 					line_number++;
2216 				}
2217 				if ((source != NULL) &&
2218 				    (*++source_p == (int) nul_char)) {
2219 					GET_NEXT_BLOCK(source);
2220 					if (source == NULL) {
2221 						GOTO_STATE(on_eoln_state);
2222 					}
2223 				}
2224 			} while (*source_p == (int) newline_char);
2225 
2226 			GOTO_STATE(enter_dependencies_state);
2227 		case nul_char:
2228 			if (!macro_seen_in_string) {
2229 				INIT_STRING_FROM_STACK(name_string,
2230 						       name_buffer);
2231 			}
2232 			append_string(string_start,
2233 				      &name_string,
2234 				      source_p - string_start);
2235 			macro_seen_in_string = true;
2236 			GET_NEXT_BLOCK(source);
2237 			string_start = source_p;
2238 			source_p--;
2239 			if (source == NULL) {
2240 				GOTO_STATE(enter_dependencies_state);
2241 			}
2242 			break;
2243 		}
2244 	}
2245 
2246 /****************************************************************
2247  *	enter equal state
2248  */
2249 case enter_equal_state:
2250 	if (target.used != 1) {
2251 		GOTO_STATE(poorly_formed_macro_state);
2252 	}
2253 	if (append && expand)			/* +:= seen */
2254 		separator = append_assign_seen;
2255 	enter_equal(target.names[0], macro_value, append, separator);
2256 	goto start_new_line;
2257 
2258 /****************************************************************
2259  *	enter conditional state
2260  */
2261 case enter_conditional_state:
2262 	if (depes.used != 1) {
2263 		GOTO_STATE(poorly_formed_macro_state);
2264 	}
2265 	for (nvp = &target; nvp != NULL; nvp = nvp->next) {
2266 		for (i = 0; i < nvp->used; i++) {
2267 			enter_conditional(nvp->names[i],
2268 					  depes.names[0],
2269 					  macro_value,
2270 					  append);
2271 		}
2272 	}
2273 	goto start_new_line;
2274 
2275 /****************************************************************
2276  *	Error states
2277  */
2278 case illegal_bytes_state:
2279 	fatal_reader(gettext("Invalid byte sequence"));
2280 case illegal_eoln_state:
2281 	if (line_number > 1) {
2282 		if (line_started_with_space == (line_number - 1)) {
2283 			line_number--;
2284 			fatal_reader(gettext("Unexpected end of line seen\n\t*** missing separator (did you mean TAB instead of 8 spaces?)"));
2285 		}
2286 	}
2287 	fatal_reader(gettext("Unexpected end of line seen"));
2288 case poorly_formed_macro_state:
2289 	fatal_reader(gettext("Badly formed macro assignment"));
2290 case exit_state:
2291 	return;
2292 default:
2293 	fatal_reader(gettext("Internal error. Unknown reader state"));
2294 }
2295 }
2296 
2297 /*
2298  *	push_macro_value(bp, buffer, size, source)
2299  *
2300  *	Macro and function that evaluates one macro
2301  *	and makes the reader read from the value of it
2302  *
2303  *	Return value:
2304  *				The source block to read the macro from
2305  *
2306  *	Parameters:
2307  *		bp		The new source block to fill in
2308  *		buffer		Buffer to read from
2309  *		size		size of the buffer
2310  *		source		The old source block
2311  *
2312  *	Global variables used:
2313  */
2314 static Source
push_macro_value(register Source bp,register wchar_t * buffer,int size,register Source source)2315 push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source)
2316 {
2317 	bp->string.buffer.start = bp->string.text.p = buffer;
2318 	bp->string.text.end = NULL;
2319 	bp->string.buffer.end = buffer + (size/SIZEOFWCHAR_T);
2320 	bp->string.free_after_use = false;
2321 	bp->inp_buf =
2322 	  bp->inp_buf_ptr =
2323 	    bp->inp_buf_end = NULL;
2324 	bp->error_converting = false;
2325 	expand_macro(source, &bp->string, (wchar_t *) NULL, false, no_expand);
2326 	bp->string.text.p = bp->string.buffer.start;
2327 
2328 	/* 4209588: 'make' doesn't understand a macro with whitespaces in the head as target.
2329 	 * strip whitespace from the begining of the macro value
2330 	 */
2331 	while (iswspace(*bp->string.text.p)) {
2332 		bp->string.text.p++;
2333 	}
2334 
2335 	bp->fd = -1;
2336 	bp->already_expanded = true;
2337 	bp->previous = source;
2338 	return bp;
2339 }
2340 
2341 /*
2342  *	enter_target_groups_and_dependencies(target, depes, command, separator,
2343  *					     target_group_seen)
2344  *
2345  *	Parameters:
2346  *		target 		Structure that shows the target(s) on the line
2347  *				we are currently parsing. This can looks like
2348  *				target1 .. targetN : dependencies
2349  *						  	commands
2350  *				or
2351  *				target1 + .. + targetN : dependencies
2352  *							 commands
2353  *		depes		Dependencies
2354  *		command		Points to the command(s) to be executed for
2355  *				this target.
2356  *		separator	: or :: or :=
2357  *		target_group_seen	Set if we have target1 + .. + targetN
2358  *
2359  *
2360  * 	After reading the command lines for a target, this routine
2361  *	is called to setup the dependencies and the commands for it.
2362  * 	If the target is a % pattern or part of a target group, then
2363  *  	the appropriate routines are called.
2364  */
2365 
2366 void
enter_target_groups_and_dependencies(Name_vector target,Name_vector depes,Cmd_line command,Separator separator,Boolean target_group_seen)2367 enter_target_groups_and_dependencies(Name_vector target, Name_vector depes, Cmd_line command, Separator separator, Boolean target_group_seen)
2368 {
2369 	int			i;
2370 	Boolean			reset= true;
2371 	Chain			target_group_member;
2372 	Percent			percent_ptr;
2373 
2374 	for (; target != NULL; target = target->next) {
2375 		for (i = 0; i < target->used; i++) {
2376 			if (target->names[i] != NULL) {
2377 				if (target_group_seen) {
2378 					target_group_member =
2379 					  find_target_groups(target, i, reset);
2380 					if(target_group_member == NULL) {
2381 						fatal_reader(gettext("Unexpected '+' on dependency line"));
2382 					}
2383 				}
2384 				reset = false;
2385 
2386 				/* If we saw it in the makefile it must be
2387 				 * a file */
2388 				target->names[i]->stat.is_file = true;
2389 				/* Make sure that we use dependencies
2390 				 * entered for makefiles */
2391 				target->names[i]->state = build_dont_know;
2392 
2393 				/* If the target is special we delegate
2394 				 * the processing */
2395 				if (target->names[i]->special_reader
2396 				    != no_special) {
2397 					special_reader(target->names[i],
2398 						       depes,
2399 						       command,
2400 						       separator);
2401 				}
2402 				/* Check if this is a "a%b : x%y" type rule */
2403 				else if (target->names[i]->percent) {
2404 					percent_ptr =
2405 					  enter_percent(target->names[i],
2406 							target->target_group[i],
2407 							depes, command);
2408 					if (target_group_seen) {
2409 						target_group_member->percent_member =
2410 						  percent_ptr;
2411 					}
2412 				} else if (target->names[i]->dollar) {
2413 					enter_dyntarget(target->names[i]);
2414 					enter_dependencies
2415 					  (target->names[i],
2416 					   target->target_group[i],
2417 					   depes,
2418 					   command,
2419 					   separator);
2420 				} else {
2421 					if (target_group_seen) {
2422 						target_group_member->percent_member =
2423 						  NULL;
2424 					}
2425 
2426 					enter_dependencies
2427 					  (target->names[i],
2428 					   target->target_group[i],
2429 					   depes,
2430 					   command,
2431 					   separator);
2432 				}
2433 			}
2434 		}
2435 	}
2436 }
2437 
2438 void
doexport(Name name)2439 doexport(Name name)
2440 {
2441 	Name		val;
2442 	char		*eval;
2443 	size_t		len;
2444 
2445 	if (strcmp(name->string_mb, NOCATGETS("SHELL")) == 0)
2446 		return;
2447 
2448 	val = getvar(name);
2449 	len = strlen(name->string_mb) + 1 + strlen(val->string_mb) + 1;
2450 	eval = (char *)malloc(len);
2451 	strcpy(eval, name->string_mb);
2452 	strcat(eval, "=");
2453 	strcat(eval, val->string_mb);
2454 
2455 	putenv(eval);
2456 }
2457 
2458 void
dounexport(Name name)2459 dounexport(Name name)
2460 {
2461 	Name		val;
2462 	char		*eval;
2463 	size_t		len;
2464 
2465 	if (strcmp(name->string_mb, NOCATGETS("SHELL")) == 0)
2466 		return;
2467 
2468 	unsetenv(name->string_mb);
2469 }
2470 
2471 void
doreadonly(Name name)2472 doreadonly(Name name)
2473 {
2474 	Property	macro;
2475 
2476 	if ((macro = get_prop(name->prop, macro_prop)) != NULL)
2477 		macro->body.macro.read_only = true;
2478 }
2479 
2480 static Boolean
skip_comment(wchar_t * & source_p,wchar_t * & source_end,Source & source)2481 skip_comment(wchar_t * &source_p, wchar_t * &source_end, Source &source)
2482 {
2483 	/* Comment. Skip over it */
2484 	for (; 1; source_p++) {
2485 		switch (GET_CHAR()) {
2486 		case nul_char:
2487 			GET_NEXT_BLOCK_NOCHK(source);
2488 			if (source == NULL) {
2489 				return (false);
2490 			}
2491 			if (source->error_converting) {
2492 			// Illegal byte sequence - skip its first byte
2493 				source->inp_buf_ptr++;
2494 			}
2495 			source_p--;
2496 			break;
2497 		case backslash_char:
2498 			/* Comments can be continued */
2499 			if (*++source_p == (int) nul_char) {
2500 				GET_NEXT_BLOCK_NOCHK(source);
2501 				if (source == NULL) {
2502 					return (false);
2503 				}
2504 				if (source->error_converting) {
2505 				// Illegal byte sequence - skip its first byte
2506 					source->inp_buf_ptr++;
2507 					source_p--;
2508 					break;
2509 				}
2510 			}
2511 			if(*source_p == (int) newline_char) {
2512 				if (source->fd >= 0) {
2513 					line_number++;
2514 				}
2515 			}
2516 			break;
2517 		case newline_char:
2518 			return (true);
2519 		}
2520 	}
2521 }
2522 
2523 static void
init_directives(void)2524 init_directives(void)
2525 {
2526 	MBSTOWCS(include_d,  NOCATGETS("include "));
2527 	MBSTOWCS(iinclude_d, NOCATGETS("-include "));
2528 	MBSTOWCS(export_d,   NOCATGETS("export "));
2529 	MBSTOWCS(unexport_d, NOCATGETS("unexport "));
2530 	MBSTOWCS(readonly_d, NOCATGETS("readonly "));
2531 }
2532