xref: /illumos-gate/usr/src/lib/libc/port/stdio/fwrite.c (revision cd62a92d)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 #include "lint.h"
31 #include "file64.h"
32 #include "mtlib.h"
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <values.h>
36 #include <memory.h>
37 #include <thread.h>
38 #include <synch.h>
39 #include <unistd.h>
40 #include "stdiom.h"
41 #include "mse.h"
42 
43 size_t
44 _fwrite_unlocked(const void *ptr, size_t size, size_t count, FILE *iop);
45 
46 size_t
fwrite(const void * ptr,size_t size,size_t count,FILE * iop)47 fwrite(const void *ptr, size_t size, size_t count, FILE *iop)
48 {
49 	rmutex_t	*lk;
50 	size_t	retval;
51 
52 	FLOCKFILE(lk, iop);
53 
54 	_SET_ORIENTATION_BYTE(iop);
55 
56 	retval = _fwrite_unlocked(ptr, size, count, iop);
57 	FUNLOCKFILE(lk);
58 
59 	return (retval);
60 }
61 
62 size_t
_fwrite_unlocked(const void * ptr,size_t size,size_t count,FILE * iop)63 _fwrite_unlocked(const void *ptr, size_t size, size_t count, FILE *iop)
64 {
65 	ssize_t s, n;
66 	unsigned char *dptr = (unsigned char *)ptr;
67 	unsigned char *bufend;
68 
69 	if (_WRTCHK(iop))
70 		return (0);
71 
72 	/*
73 	 * This test is here to avoid the expensive multiply
74 	 */
75 	if (count == 1)
76 		s = size;
77 	else if (size == 1)
78 		s = count;
79 	else
80 		s = size * count;
81 
82 	if (iop->_flag & _IOLBF) {
83 		bufend = _bufend(iop);
84 		iop->_cnt = iop->_base - iop->_ptr;
85 		while (s > 0) {
86 			ssize_t buflen = bufend - iop->_base;
87 			if (--iop->_cnt >= (-buflen) && *dptr != '\n')
88 				*iop->_ptr++ = *dptr++;
89 			else if (__flsbuf(*dptr++, iop) == EOF)
90 				break;
91 			s--;
92 		}
93 	} else if (iop->_flag & _IONBF) {
94 		ssize_t bytes;
95 		ssize_t written = 0;
96 		char *data;
97 
98 		if (size < 1 || count < 1)
99 			return (0);
100 
101 		if (iop->_base != iop->_ptr) {
102 		/*
103 		 * Flush any existing data. Doesn't count towards return
104 		 * value.
105 		 */
106 			bytes = iop->_ptr - iop->_base;
107 			data = (char *)iop->_base;
108 
109 			while ((n = _xwrite(iop, data, (size_t)bytes)) !=
110 			    bytes) {
111 				if (n <= 0) {
112 					if (!cancel_active())
113 						iop->_flag |= _IOERR;
114 					return (0);
115 				} else {
116 					data += n;
117 					bytes -= n;
118 				}
119 			}
120 			iop->_cnt = 0;
121 			iop->_ptr = iop->_base;
122 		}
123 		/*
124 		 * written is in bytes until the return.
125 		 * Then it is divided by size to produce items.
126 		 */
127 		while ((n = _xwrite(iop, dptr, s)) != s) {
128 			if (n <= 0) {
129 				if (!cancel_active())
130 					iop->_flag |= _IOERR;
131 				return (written / size);
132 			} else {
133 				dptr += n;
134 				s -= n;
135 				written += n;
136 			}
137 		}
138 		written += n;
139 		return (written / size);
140 	} else while (s > 0) {
141 		if (iop->_cnt < s) {
142 			if (iop->_cnt > 0) {
143 				(void) memcpy(iop->_ptr, (void *)dptr,
144 				    iop->_cnt);
145 				dptr += iop->_cnt;
146 				iop->_ptr += iop->_cnt;
147 				s -= iop->_cnt;
148 			}
149 			if (_xflsbuf(iop) == EOF)
150 				break;
151 		}
152 		if (iop->_cnt >= s) {
153 			char *tmp = (char *)iop->_ptr;
154 
155 			switch (s) {
156 			case 8:
157 				*tmp++ = *dptr++;
158 				/*FALLTHRU*/
159 			case 7:
160 				*tmp++ = *dptr++;
161 				/*FALLTHRU*/
162 			case 6:
163 				*tmp++ = *dptr++;
164 				/*FALLTHRU*/
165 			case 5:
166 				*tmp++ = *dptr++;
167 				/*FALLTHRU*/
168 			case 4:
169 				*tmp++ = *dptr++;
170 				/*FALLTHRU*/
171 			case 3:
172 				*tmp++ = *dptr++;
173 				/*FALLTHRU*/
174 			case 2:
175 				*tmp++ = *dptr++;
176 				/*FALLTHRU*/
177 			case 1:
178 				*tmp++ = *dptr++;
179 				break;
180 			case 0:
181 				return (count);
182 			default:
183 				(void) memcpy(iop->_ptr, (void *)dptr, s);
184 			}
185 			iop->_ptr += s;
186 			iop->_cnt -= s;
187 
188 			return (count);
189 		}
190 	}
191 
192 	return (size != 0 ? count - ((s + size - 1) / size) : 0);
193 }
194