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 2004 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)read.cc 1.11 06/12/12
29  */
30 
31 #pragma	ident	"@(#)read.cc	1.11	06/12/12"
32 
33 /*
34  * Copyright 2017-2018 J. Schilling
35  *
36  * @(#)read.cc	1.6 21/08/15 2017-2018 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)read.cc	1.6 21/08/15 2017-2018 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 <mksh/misc.h>		/* retmem() */
54 #include <mksh/read.h>
55 #include <sys/uio.h>		/* read() */
56 
57 #define	STRING_LEN_TO_CONVERT	(8*1024)
58 
59 /*
60  *	get_next_block_fn(source)
61  *
62  *	Will get the next block of text to read either
63  *	by popping one source bVSIZEOFlock of the stack of Sources
64  *	or by reading some more from the makefile.
65  *
66  *	Return value:
67  *				The new source block to read from
68  *
69  *	Parameters:
70  *		source		The old source block
71  *
72  *	Global variables used:
73  *		file_being_read	The name of the current file, error msg
74  */
75 Boolean		make_state_locked;
76 Source
get_next_block_fn(register Source source)77 get_next_block_fn(register Source source)
78 {
79 	register off_t		to_read;
80 	register int		length;
81 	register size_t		num_wc_chars;
82 	char			ch_save;
83 	char			*ptr;
84 
85 	if (source == NULL) {
86 		return NULL;
87 	}
88 	if ((source->fd < 0) ||
89 		((source->bytes_left_in_file <= 0) &&
90 			(source->inp_buf_ptr >= source->inp_buf_end))) {
91 		/* We can't read from the makefile, so pop the source block */
92 		if (source->fd > 2) {
93 			(void) close(source->fd);
94 			if (make_state_lockfile != NULL) {
95 				(void) unlink(make_state_lockfile);
96 				retmem_mb(make_state_lockfile);
97 				make_state_lockfile = NULL;
98 				make_state_locked = false;
99 			}
100 		}
101 		if (source->string.free_after_use &&
102 		    (source->string.buffer.start != NULL)) {
103 			retmem(source->string.buffer.start);
104 			source->string.buffer.start = NULL;
105 		}
106 		if (source->inp_buf != NULL) {
107 			retmem_mb(source->inp_buf);
108 			source->inp_buf = NULL;
109 		}
110 		source = source->previous;
111 		if (source != NULL) {
112 			source->error_converting = false;
113 		}
114 		return source;
115 	}
116 	if (source->bytes_left_in_file > 0) {
117 	/*
118 	 * Read the whole makefile.
119 	 * Hopefully the kernel managed to prefetch the stuff.
120 	 */
121 		to_read = source->bytes_left_in_file;
122 	 	source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
123 		source->inp_buf_end = source->inp_buf + to_read;
124 		length = read(source->fd, source->inp_buf, (unsigned int) to_read);
125 		if (length != to_read) {
126 			WCSTOMBS(mbs_buffer, file_being_read);
127 			if (length == 0) {
128 				fatal_mksh(gettext("Error reading `%s': Premature EOF"),
129 				      mbs_buffer);
130 			} else {
131 				fatal_mksh(gettext("Error reading `%s': %s"),
132 				      mbs_buffer,
133 				      errmsg(errno));
134 			}
135 		}
136 		*source->inp_buf_end = nul_char;
137 		source->bytes_left_in_file = 0;
138 	}
139 	/*
140 	 * Try to convert the next piece.
141 	 */
142 	ptr = source->inp_buf_ptr + STRING_LEN_TO_CONVERT;
143 	if (ptr > source->inp_buf_end) {
144 		ptr = source->inp_buf_end;
145 	}
146 	for (num_wc_chars = 0; ptr > source->inp_buf_ptr; ptr--) {
147 		ch_save = *ptr;
148 		*ptr = nul_char;
149 		num_wc_chars = mbstowcs(source->string.text.end,
150 					source->inp_buf_ptr,
151 					STRING_LEN_TO_CONVERT);
152 		*ptr = ch_save;
153 		if (num_wc_chars != (size_t)-1) {
154 			break;
155 		}
156 	}
157 
158 	if ((int) num_wc_chars == (size_t)-1) {
159 		source->error_converting = true;
160 		return source;
161 	}
162 
163 	source->error_converting = false;
164 	source->inp_buf_ptr = ptr;
165 	source->string.text.end += num_wc_chars;
166 	*source->string.text.end = 0;
167 
168 	if (source->inp_buf_ptr >= source->inp_buf_end) {
169 		if (*(source->string.text.end - 1) != (int) newline_char) {
170 			WCSTOMBS(mbs_buffer, file_being_read);
171 			warning_mksh(gettext("newline is not last character in file %s"),
172 					     mbs_buffer);
173 			*source->string.text.end++ = (int) newline_char;
174 			*source->string.text.end = (int) nul_char;
175 		}
176 		if (source->inp_buf != NULL) {
177 			retmem_mb(source->inp_buf);
178 			source->inp_buf = NULL;
179 		}
180 	}
181 	return source;
182 }
183 
184 
185