Fix: pass private data to context callbacks
[lttng-ust.git] / snprintf / fvwrite.c
CommitLineData
bf0d695d 1/* $OpenBSD: fvwrite.c,v 1.16 2009/10/22 01:23:16 guenther Exp $ */
c0c0989a
MJ
2/*
3 * SPDX-License-Identifier: BSD-3-Clause
4 *
5 * Copyright (C) 1990, 1993
bf0d695d
PMF
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Chris Torek.
bf0d695d
PMF
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <errno.h>
16#include "local.h"
17#include "fvwrite.h"
18#include "various.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 */
26int
002e1fde 27__sfvwrite(LTTNG_UST_LFILE *fp, struct __lttng_ust_suio *uio)
bf0d695d
PMF
28{
29 size_t len;
30 char *p;
002e1fde 31 struct __lttng_ust_siov *iov;
bf0d695d
PMF
32 int w, s;
33 char *nl;
34 int nlknown, nldist;
35
36 if ((len = uio->uio_resid) == 0)
37 return (0);
38 /* make sure we can write */
39 if (cantwrite(fp)) {
40 errno = EBADF;
41 return (EOF);
42 }
43
44#define MIN(a, b) ((a) < (b) ? (a) : (b))
45#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
46
47 iov = uio->uio_iov;
48 p = iov->iov_base;
49 len = iov->iov_len;
50 iov++;
51#define GETIOV(extra_work) \
52 while (len == 0) { \
53 extra_work; \
54 p = iov->iov_base; \
55 len = iov->iov_len; \
56 iov++; \
57 }
58 if (fp->_flags & __SNBF) {
59 /*
60 * Unbuffered: write up to BUFSIZ bytes at a time.
61 */
62 do {
63 GETIOV(;);
64 w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ));
65 if (w <= 0)
66 goto err;
67 p += w;
68 len -= w;
69 } while ((uio->uio_resid -= w) != 0);
70 } else if ((fp->_flags & __SLBF) == 0) {
71 /*
72 * Fully buffered: fill partially full buffer, if any,
73 * and then flush. If there is no partial buffer, write
74 * one _bf._size byte chunk directly (without copying).
75 *
76 * String output is a special case: write as many bytes
77 * as fit, but pretend we wrote everything. This makes
78 * snprintf() return the number of bytes needed, rather
79 * than the number used, and avoids its write function
80 * (so that the write function can be invalid).
81 */
82 do {
83 GETIOV(;);
84 if ((fp->_flags & (__SALC | __SSTR)) ==
85 (__SALC | __SSTR) && fp->_w < len) {
86 size_t blen = fp->_p - fp->_bf._base;
87 unsigned char *_base;
88 int _size;
89
90 /* Allocate space exponentially. */
91 _size = fp->_bf._size;
92 do {
93 _size = (_size << 1) + 1;
94 } while (_size < blen + len);
95 _base = realloc(fp->_bf._base, _size + 1);
96 if (_base == NULL)
97 goto err;
98 fp->_w += _size - fp->_bf._size;
99 fp->_bf._base = _base;
100 fp->_bf._size = _size;
101 fp->_p = _base + blen;
102 }
103 w = fp->_w;
104 if (fp->_flags & __SSTR) {
105 if (len < w)
106 w = len;
107 COPY(w); /* copy MIN(fp->_w,len), */
108 fp->_w -= w;
109 fp->_p += w;
110 w = len; /* but pretend copied all */
111 } else if (fp->_p > fp->_bf._base && len > w) {
112 /* fill and flush */
113 COPY(w);
114 /* fp->_w -= w; */ /* unneeded */
115 fp->_p += w;
116 if (ust_safe_fflush(fp))
117 goto err;
118 } else if (len >= (w = fp->_bf._size)) {
119 /* write directly */
120 w = (*fp->_write)(fp->_cookie, p, w);
121 if (w <= 0)
122 goto err;
123 } else {
124 /* fill and done */
125 w = len;
126 COPY(w);
127 fp->_w -= w;
128 fp->_p += w;
129 }
130 p += w;
131 len -= w;
132 } while ((uio->uio_resid -= w) != 0);
133 } else {
134 /*
135 * Line buffered: like fully buffered, but we
136 * must check for newlines. Compute the distance
137 * to the first newline (including the newline),
138 * or `infinity' if there is none, then pretend
139 * that the amount to write is MIN(len,nldist).
140 */
141 nlknown = 0;
142 nldist = 0; /* XXX just to keep gcc happy */
143 do {
144 GETIOV(nlknown = 0);
145 if (!nlknown) {
146 nl = memchr((void *)p, '\n', len);
147 nldist = nl ? nl + 1 - p : len + 1;
148 nlknown = 1;
149 }
150 s = MIN(len, nldist);
151 w = fp->_w + fp->_bf._size;
152 if (fp->_p > fp->_bf._base && s > w) {
153 COPY(w);
154 /* fp->_w -= w; */
155 fp->_p += w;
156 if (ust_safe_fflush(fp))
157 goto err;
158 } else if (s >= (w = fp->_bf._size)) {
159 w = (*fp->_write)(fp->_cookie, p, w);
160 if (w <= 0)
161 goto err;
162 } else {
163 w = s;
164 COPY(w);
165 fp->_w -= w;
166 fp->_p += w;
167 }
168 if ((nldist -= w) == 0) {
169 /* copied the newline: flush and forget */
170 if (ust_safe_fflush(fp))
171 goto err;
172 nlknown = 0;
173 }
174 p += w;
175 len -= w;
176 } while ((uio->uio_resid -= w) != 0);
177 }
178 return (0);
179
180err:
181 fp->_flags |= __SERR;
182 return (EOF);
183}
This page took 0.036963 seconds and 4 git commands to generate.