Make all bucket and overflow addresses unsigned
[unix-history] / usr / src / lib / libc / stdio / fvwrite.c
CommitLineData
c9be6cfe
KB
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#if defined(LIBC_SCCS) && !defined(lint)
de26385f 12static char sccsid[] = "@(#)fvwrite.c 5.2 (Berkeley) %G%";
c9be6cfe
KB
13#endif /* LIBC_SCCS and not lint */
14
15#include <stdio.h>
16#include <string.h>
17#include "local.h"
18#include "fvwrite.h"
19
20/*
21 * Write some memory regions. Return zero on success, EOF on error.
22 *
23 * This routine is large and unsightly, but most of the ugliness due
24 * to the three different kinds of output buffering is handled here.
25 */
26__sfvwrite(fp, uio)
27 register FILE *fp;
28 register struct __suio *uio;
29{
30 register size_t len;
31 register char *p;
32 register struct __siov *iov;
33 register int w, s;
34 char *nl;
35 int nlknown, nldist;
36
37 if ((len = uio->uio_resid) == 0)
38 return (0);
39 /* make sure we can write */
40 if (cantwrite(fp))
41 return (EOF);
42
43#define MIN(a, b) ((a) < (b) ? (a) : (b))
44#define COPY(n) (void) memcpy((void *)fp->_p, (void *)p, (size_t)(n));
45
46 iov = uio->uio_iov;
de26385f
CT
47 p = iov->iov_base;
48 len = iov->iov_len;
49 iov++;
c9be6cfe
KB
50#define GETIOV(extra_work) \
51 while (len == 0) { \
52 extra_work; \
53 p = iov->iov_base; \
54 len = iov->iov_len; \
55 iov++; \
56 }
57 if (fp->_flags & __SNBF) {
58 /*
59 * Unbuffered: write up to BUFSIZ bytes at a time.
60 */
61 do {
62 GETIOV(;);
63 w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ));
64 if (w <= 0)
65 goto err;
66 p += w;
67 len -= w;
68 } while ((uio->uio_resid -= w) != 0);
69 } else if ((fp->_flags & __SLBF) == 0) {
70 /*
71 * Fully buffered: fill partially full buffer, if any,
72 * and then flush. If there is no partial buffer, write
73 * one _bf._size byte chunk directly (without copying).
74 *
75 * String output is a special case: write as many bytes
76 * as fit, but pretend we wrote everything. This makes
77 * snprintf() return the number of bytes needed, rather
78 * than the number used, and avoids its write function
79 * (so that the write function can be invalid).
80 */
81 do {
82 GETIOV(;);
83 w = fp->_w;
84 if (fp->_flags & __SSTR) {
85 if (len < w)
86 w = len;
87 COPY(w); /* copy MIN(fp->_w,len), */
88 fp->_w -= w;
89 fp->_p += w;
90 w = len; /* but pretend copied all */
91 } else if (fp->_p > fp->_bf._base && len > w) {
92 /* fill and flush */
93 COPY(w);
94 /* fp->_w -= w; */ /* unneeded */
95 fp->_p += w;
96 if (fflush(fp))
97 goto err;
98 } else if (len >= (w = fp->_bf._size)) {
99 /* write directly */
100 w = (*fp->_write)(fp->_cookie, p, w);
101 if (w <= 0)
102 goto err;
103 } else {
104 /* fill and done */
105 w = len;
106 COPY(w);
107 fp->_w -= w;
108 fp->_p += w;
109 }
110 p += w;
111 len -= w;
112 } while ((uio->uio_resid -= w) != 0);
113 } else {
114 /*
115 * Line buffered: like fully buffered, but we
116 * must check for newlines. Compute the distance
117 * to the first newline (including the newline),
118 * or `infinity' if there is none, then pretend
119 * that the amount to write is MIN(len,nldist).
120 */
121 nlknown = 0;
de26385f 122 nldist = 0; /* XXX just to keep gcc happy */
c9be6cfe
KB
123 do {
124 GETIOV(nlknown = 0);
125 if (!nlknown) {
126 nl = memchr((void *)p, '\n', len);
127 nldist = nl ? nl + 1 - p : len + 1;
128 nlknown = 1;
129 }
130 s = MIN(len, nldist);
131 w = fp->_w + fp->_bf._size;
132 if (fp->_p > fp->_bf._base && s > w) {
133 COPY(w);
134 /* fp->_w -= w; */
135 fp->_p += w;
136 if (fflush(fp))
137 goto err;
138 } else if (s >= (w = fp->_bf._size)) {
139 w = (*fp->_write)(fp->_cookie, p, w);
140 if (w <= 0)
141 goto err;
142 } else {
143 w = s;
144 COPY(w);
145 fp->_w -= w;
146 fp->_p += w;
147 }
148 if ((nldist -= w) == 0) {
149 /* copied the newline: flush and forget */
150 if (fflush(fp))
151 goto err;
152 nlknown = 0;
153 }
154 p += w;
155 len -= w;
156 } while ((uio->uio_resid -= w) != 0);
157 }
158 return (0);
159
160err:
161 fp->_flags |= __SERR;
162 return (EOF);
163}