4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include "streams_wide.h"
29 #include "streams_common.h"
31 #define WIDE_VBUF_SIZE (64 * KILOBYTE)
33 #define SHELF_OCCUPIED 1
34 #define SHELF_VACANT 0
35 static int shelf
= SHELF_VACANT
;
38 * Wide character streams implementation
40 * The wide character streams implementation is, for the most part, a
41 * reimplementation of the stdio streams implementation, using wide character
42 * string routines. However, fgetws(3C) retains the newline that fgets(3C)
43 * discards while reading a complete line. As a result, the wide character
44 * routines need to guard against coincidental exhaustion of the buffer, as
45 * well as overwriting the end-of-line character and correcting the
46 * l_data_length field.
50 stream_wide_prime(stream_t
*str
)
52 stream_buffered_file_t
*BF
= &(str
->s_type
.BF
);
53 wchar_t *current_position
;
54 wchar_t *end_of_buffer
;
57 ASSERT(!(str
->s_status
& STREAM_OUTPUT
));
58 ASSERT(str
->s_status
& STREAM_OPEN
);
60 if (str
->s_status
& STREAM_INSTANT
&& (str
->s_buffer
== NULL
)) {
61 str
->s_buffer
= xzmap(0, WIDE_VBUF_SIZE
, PROT_READ
|
62 PROT_WRITE
, MAP_PRIVATE
, 0);
63 if (str
->s_buffer
== MAP_FAILED
)
65 str
->s_buffer_size
= WIDE_VBUF_SIZE
;
68 ASSERT(str
->s_buffer
!= NULL
);
70 if (stream_is_primed(str
)) {
71 int shelf_state
= shelf
;
73 ASSERT(str
->s_current
.l_data_length
>= -1);
74 (void) memcpy(str
->s_buffer
, str
->s_current
.l_data
.wp
,
75 (str
->s_current
.l_data_length
+ 1) * sizeof (wchar_t));
76 str
->s_current
.l_data
.wp
= str
->s_buffer
;
78 if ((str
->s_current
.l_data_length
== -1 ||
79 shelf_state
== SHELF_OCCUPIED
||
80 *(str
->s_current
.l_data
.wp
+
81 str
->s_current
.l_data_length
) != L
'\0') &&
82 SOP_FETCH(str
) == NEXT_LINE_INCOMPLETE
&&
83 shelf_state
== SHELF_OCCUPIED
)
86 return (PRIME_SUCCEEDED
);
89 stream_set(str
, STREAM_PRIMED
);
91 current_position
= (wchar_t *)str
->s_buffer
;
93 end_of_buffer
= (wchar_t *)((char *)str
->s_buffer
+
98 (void) fgetws(current_position
, end_of_buffer
99 - current_position
, BF
->s_fp
);
101 stream_set(str
, STREAM_EOS_REACHED
);
102 stream_unset(str
, STREAM_PRIMED
);
103 return (PRIME_FAILED_EMPTY_FILE
);
106 str
->s_current
.l_data
.wp
= current_position
;
107 next_nl
= xmemwchar(current_position
, L
'\n', end_of_buffer
-
109 if (next_nl
== NULL
) {
110 warn(WMSG_NEWLINE_ADDED
, str
->s_filename
);
111 str
->s_current
.l_data_length
= MIN(wslen(current_position
),
112 end_of_buffer
- current_position
);
114 str
->s_current
.l_data_length
= next_nl
- current_position
;
116 *(str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
) = L
'\0';
118 str
->s_current
.l_collate
.wp
= NULL
;
119 str
->s_current
.l_collate_length
= 0;
121 __S(stats_incr_fetches());
122 return (PRIME_SUCCEEDED
);
126 stream_wide_fetch(stream_t
*str
)
128 ssize_t dist_to_buf_end
;
133 ASSERT(str
->s_status
& STREAM_OPEN
);
134 ASSERT((str
->s_status
& STREAM_EOS_REACHED
) == 0);
136 graft_pt
= str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
+ 1;
138 if (shelf
== SHELF_VACANT
)
139 str
->s_current
.l_data
.wp
= graft_pt
;
140 else if (str
->s_current
.l_data_length
> -1)
143 dist_to_buf_end
= str
->s_buffer_size
/ sizeof (wchar_t) - (graft_pt
-
144 (wchar_t *)str
->s_buffer
);
146 if (dist_to_buf_end
<= 1) {
147 str
->s_current
.l_data_length
= -1;
148 return (NEXT_LINE_INCOMPLETE
);
151 if (fgetws(graft_pt
, dist_to_buf_end
, str
->s_type
.BF
.s_fp
) == NULL
) {
152 if (feof(str
->s_type
.BF
.s_fp
))
153 stream_set(str
, STREAM_EOS_REACHED
);
155 die(EMSG_READ
, str
->s_filename
);
158 trip_eof(str
->s_type
.BF
.s_fp
);
159 if ((next_nl
= xmemwchar(str
->s_current
.l_data
.wp
, L
'\n',
160 dist_to_buf_end
)) == NULL
) {
161 str
->s_current
.l_data_length
=
162 MIN(wslen(str
->s_current
.l_data
.wp
), dist_to_buf_end
);
164 str
->s_current
.l_data_length
= next_nl
-
165 str
->s_current
.l_data
.wp
;
168 str
->s_current
.l_collate_length
= 0;
170 if (*(str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
) !=
172 if (!feof(str
->s_type
.BF
.s_fp
)) {
173 if (shelf
== SHELF_OCCUPIED
)
176 shelf
= SHELF_OCCUPIED
;
177 ret_val
= NEXT_LINE_INCOMPLETE
;
178 __S(stats_incr_shelves());
180 stream_set(str
, STREAM_EOS_REACHED
);
181 warn(WMSG_NEWLINE_ADDED
, str
->s_filename
);
184 shelf
= SHELF_VACANT
;
185 ret_val
= NEXT_LINE_COMPLETE
;
186 *(str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
) =
188 __S(stats_incr_fetches());
195 stream_wide_fetch_overwrite(stream_t
*str
)
197 ssize_t dist_to_buf_end
;
199 ASSERT(str
->s_status
& STREAM_OPEN
);
200 ASSERT((str
->s_status
& STREAM_EOS_REACHED
) == 0);
202 str
->s_current
.l_data
.wp
= str
->s_buffer
;
203 dist_to_buf_end
= str
->s_buffer_size
/ sizeof (wchar_t);
205 if (fgetws(str
->s_current
.l_data
.wp
, dist_to_buf_end
,
206 str
->s_type
.BF
.s_fp
) == NULL
) {
207 if (feof(str
->s_type
.BF
.s_fp
))
208 stream_set(str
, STREAM_EOS_REACHED
);
210 die(EMSG_READ
, str
->s_filename
);
213 trip_eof(str
->s_type
.BF
.s_fp
);
214 str
->s_current
.l_data_length
= wslen(str
->s_current
.l_data
.wp
) - 1;
215 str
->s_current
.l_collate_length
= 0;
217 if (str
->s_current
.l_data_length
== -1 ||
218 *(str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
) !=
220 if (!feof(str
->s_type
.BF
.s_fp
)) {
223 stream_set(str
, STREAM_EOS_REACHED
);
224 warn(WMSG_NEWLINE_ADDED
, str
->s_filename
);
225 str
->s_current
.l_data_length
++;
229 *(str
->s_current
.l_data
.wp
+ str
->s_current
.l_data_length
) = L
'\0';
231 __S(stats_incr_fetches());
232 return (NEXT_LINE_COMPLETE
);
236 stream_wide_send_eol(stream_t
*str
)
238 wchar_t w_crlf
[2] = { L
'\n', L
'\0' };
240 ASSERT(str
->s_status
& STREAM_OPEN
);
241 ASSERT(str
->s_status
& STREAM_OUTPUT
);
243 if (wxwrite(str
->s_type
.SF
.s_fd
, w_crlf
) < 0)
244 die(EMSG_WRITE
, str
->s_filename
);
248 stream_wide_put_line(stream_t
*str
, line_rec_t
*line
)
250 ASSERT(str
->s_status
& STREAM_OPEN
);
251 ASSERT(str
->s_status
& STREAM_OUTPUT
);
253 if (line
->l_data_length
>= 0) {
254 if (wxwrite(str
->s_type
.SF
.s_fd
, line
->l_data
.wp
) >= 0) {
255 stream_wide_send_eol(str
);
256 __S(stats_incr_puts());
258 die(EMSG_WRITE
, str
->s_filename
);
260 safe_free(line
->l_raw_collate
.wp
);
261 line
->l_raw_collate
.wp
= NULL
;
265 stream_wide_put_line_unique(stream_t
*str
, line_rec_t
*line
)
267 static line_rec_t pvs
;
268 static size_t collate_buf_len
;
270 ASSERT(str
->s_status
& STREAM_OPEN
);
271 ASSERT(str
->s_status
& STREAM_OUTPUT
);
273 if ((pvs
.l_collate
.sp
== NULL
||
274 collated_wide(&pvs
, line
, 0, COLL_UNIQUE
) != 0) &&
275 line
->l_data_length
>= 0) {
276 stream_wide_put_line(str
, line
);
278 if (line
->l_collate_length
+ sizeof (wchar_t) >
280 pvs
.l_collate
.sp
= safe_realloc(pvs
.l_collate
.sp
,
281 line
->l_collate_length
+ sizeof (wchar_t));
282 collate_buf_len
= line
->l_collate_length
+
286 (void) memcpy(pvs
.l_collate
.sp
, line
->l_collate
.sp
,
287 line
->l_collate_length
);
288 /* LINTED ALIGNMENT */
289 *(wchar_t *)(pvs
.l_collate
.sp
+ line
->l_collate_length
) = L
'\0';
290 pvs
.l_collate_length
= line
->l_collate_length
;
295 stream_wide_eos(stream_t
*str
)
299 if (str
== NULL
|| str
->s_status
& STREAM_EOS_REACHED
)
302 trip_eof(str
->s_type
.BF
.s_fp
);
303 if (feof(str
->s_type
.BF
.s_fp
) &&
304 shelf
== SHELF_VACANT
&&
305 str
->s_current
.l_collate_length
!= -1) {
307 stream_set(str
, STREAM_EOS_REACHED
);
315 stream_wide_release_line(stream_t
*str
)
319 const stream_ops_t stream_wide_ops
= {
320 stream_stdio_is_closable
,
326 stream_stdio_open_for_write
,
328 stream_wide_put_line
,
329 stream_wide_release_line
,
330 stream_wide_send_eol
,