blob: f3a53a5061751c1df353ed5d2371e367703ae0ca [file] [log] [blame]
Chris Lattner60d39622008-08-17 01:35:29 +00001//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This implements support for bulk buffered stream output.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/raw_ostream.h"
Chris Lattner42f77ab2008-08-23 20:34:06 +000015#include "llvm/Support/Format.h"
Chris Lattner097af7f2008-08-23 19:23:10 +000016#include "llvm/ADT/SmallVector.h"
Chris Lattner969a46a2008-08-22 15:45:00 +000017#include "llvm/Config/config.h"
Chris Lattner07f51f72008-08-17 04:13:37 +000018#include <ostream>
Chris Lattner60d39622008-08-17 01:35:29 +000019
Chris Lattner969a46a2008-08-22 15:45:00 +000020#if defined(HAVE_UNISTD_H)
21# include <unistd.h>
22#endif
23#if defined(HAVE_FCNTL_H)
24# include <fcntl.h>
25#endif
Argyrios Kyrtzidisb68dc362008-08-17 09:25:21 +000026
27#if defined(_MSC_VER)
Chris Lattner60d39622008-08-17 01:35:29 +000028#include <io.h>
Cedric Veneta3f343f2008-08-24 11:56:40 +000029#include <fcntl.h>
Owen Andersoncb371882008-08-21 00:14:44 +000030#ifndef STDIN_FILENO
31# define STDIN_FILENO 0
32#endif
33#ifndef STDOUT_FILENO
34# define STDOUT_FILENO 1
35#endif
36#ifndef STDERR_FILENO
37# define STDERR_FILENO 2
38#endif
Chris Lattner60d39622008-08-17 01:35:29 +000039#endif
40
Chris Lattner969a46a2008-08-22 15:45:00 +000041using namespace llvm;
42
43
Chris Lattner60d39622008-08-17 01:35:29 +000044// An out of line virtual method to provide a home for the class vtable.
45void raw_ostream::handle() {}
46
Owen Anderson66b17ba2008-08-21 20:58:52 +000047raw_ostream &raw_ostream::operator<<(unsigned long N) {
48 // Zero is a special case.
49 if (N == 0)
50 return *this << '0';
51
52 char NumberBuffer[20];
53 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
54 char *CurPtr = EndPtr;
55
56 while (N) {
57 *--CurPtr = '0' + char(N % 10);
58 N /= 10;
59 }
60 return write(CurPtr, EndPtr-CurPtr);
61}
62
63raw_ostream &raw_ostream::operator<<(long N) {
64 if (N < 0) {
65 if (OutBufCur >= OutBufEnd)
66 flush_impl();
67 *OutBufCur++ = '-';
68
69 N = -N;
70 }
71
72 return this->operator<<(static_cast<unsigned long>(N));
73}
74
75raw_ostream &raw_ostream::operator<<(unsigned long long N) {
76 // Zero is a special case.
77 if (N == 0)
78 return *this << '0';
79
80 char NumberBuffer[20];
81 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
82 char *CurPtr = EndPtr;
83
84 while (N) {
85 *--CurPtr = '0' + char(N % 10);
86 N /= 10;
87 }
88 return write(CurPtr, EndPtr-CurPtr);
89}
90
91raw_ostream &raw_ostream::operator<<(long long N) {
92 if (N < 0) {
93 if (OutBufCur >= OutBufEnd)
94 flush_impl();
95 *OutBufCur++ = '-';
96
97 N = -N;
98 }
99
100 return this->operator<<(static_cast<unsigned long long>(N));
101}
102
Chris Lattner944fac72008-08-23 22:23:09 +0000103raw_ostream &raw_ostream::operator<<(const void *P) {
104 // FIXME: This could be much faster if it matters.
105 return *this << format("%p", P);
106}
107
108
Owen Anderson66b17ba2008-08-21 20:58:52 +0000109raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
110 if (OutBufCur+Size > OutBufEnd)
111 flush_impl();
112
113 // Handle short strings specially, memcpy isn't very good at very short
114 // strings.
115 switch (Size) {
116 case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
117 case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
118 case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
119 case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
120 case 0: break;
121 default:
122 // Normally the string to emit is shorter than the buffer.
123 if (Size <= unsigned(OutBufEnd-OutBufStart)) {
124 memcpy(OutBufCur, Ptr, Size);
125 break;
126 }
127
128 // If emitting a string larger than our buffer, emit in chunks. In this
129 // case we know that we just flushed the buffer.
130 while (Size) {
131 unsigned NumToEmit = OutBufEnd-OutBufStart;
132 if (Size < NumToEmit) NumToEmit = Size;
133 assert(OutBufCur == OutBufStart);
134 memcpy(OutBufStart, Ptr, NumToEmit);
135 Ptr += NumToEmit;
Owen Andersonfd2a0532008-08-21 22:39:33 +0000136 Size -= NumToEmit;
Owen Anderson66b17ba2008-08-21 20:58:52 +0000137 OutBufCur = OutBufStart + NumToEmit;
138 flush_impl();
139 }
140 break;
141 }
142 OutBufCur += Size;
143 return *this;
144}
145
Chris Lattner097af7f2008-08-23 19:23:10 +0000146// Formatted output.
147raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
148 // If we have more than a few bytes left in our output buffer, try formatting
149 // directly onto its end.
150 unsigned NextBufferSize = 127;
151 if (OutBufEnd-OutBufCur > 3) {
152 unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
153 unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
154
155 // Common case is that we have plenty of space.
156 if (BytesUsed < BufferBytesLeft) {
157 OutBufCur += BytesUsed;
158 return *this;
159 }
160
161 // Otherwise, we overflowed and the return value tells us the size to try
162 // again with.
163 NextBufferSize = BytesUsed;
164 }
165
166 // If we got here, we didn't have enough space in the output buffer for the
167 // string. Try printing into a SmallVector that is resized to have enough
168 // space. Iterate until we win.
169 SmallVector<char, 128> V;
170
171 while (1) {
172 V.resize(NextBufferSize);
173
174 // Try formatting into the SmallVector.
175 unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
176
177 // If BytesUsed fit into the vector, we win.
178 if (BytesUsed < NextBufferSize)
179 return write(&V[0], BytesUsed);
180
181 // Otherwise, try again with a new size.
182 assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
183 NextBufferSize = BytesUsed;
184 }
185}
186
187//===----------------------------------------------------------------------===//
188// Formatted Output
189//===----------------------------------------------------------------------===//
190
191// Out of line virtual method.
192void format_object_base::home() {
193}
194
Chris Lattner60d39622008-08-17 01:35:29 +0000195//===----------------------------------------------------------------------===//
196// raw_fd_ostream
197//===----------------------------------------------------------------------===//
198
Daniel Dunbar48534b32008-10-21 19:53:10 +0000199/// raw_fd_ostream - Open the specified file for writing. If an error
200/// occurs, information about the error is put into ErrorInfo, and the
201/// stream should be immediately destroyed; the string will be empty
202/// if no error occurred.
Chris Lattner60d39622008-08-17 01:35:29 +0000203raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo) {
Daniel Dunbar48534b32008-10-21 19:53:10 +0000204 ErrorInfo.clear();
205
Chris Lattnerc52b1282008-08-17 03:53:23 +0000206 // Handle "-" as stdout.
207 if (Filename[0] == '-' && Filename[1] == 0) {
208 FD = STDOUT_FILENO;
209 ShouldClose = false;
210 return;
211 }
212
Chris Lattner60d39622008-08-17 01:35:29 +0000213 FD = open(Filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
214 if (FD < 0) {
215 ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
216 ShouldClose = false;
217 } else {
218 ShouldClose = true;
219 }
220}
221
222raw_fd_ostream::~raw_fd_ostream() {
223 flush();
224 if (ShouldClose)
225 close(FD);
226}
227
228void raw_fd_ostream::flush_impl() {
229 if (OutBufCur-OutBufStart)
Chris Lattnerd497df52008-08-17 01:46:05 +0000230 ::write(FD, OutBufStart, OutBufCur-OutBufStart);
Chris Lattner60d39622008-08-17 01:35:29 +0000231 HandleFlush();
232}
233
Chris Lattner07f51f72008-08-17 04:13:37 +0000234//===----------------------------------------------------------------------===//
235// raw_stdout/err_ostream
236//===----------------------------------------------------------------------===//
Chris Lattner60d39622008-08-17 01:35:29 +0000237
238raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {}
239raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false) {}
240
241// An out of line virtual method to provide a home for the class vtable.
242void raw_stdout_ostream::handle() {}
243void raw_stderr_ostream::handle() {}
Chris Lattner07f51f72008-08-17 04:13:37 +0000244
245/// outs() - This returns a reference to a raw_ostream for standard output.
246/// Use it like: outs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000247raw_ostream &llvm::outs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000248 static raw_stdout_ostream S;
249 return S;
250}
251
252/// errs() - This returns a reference to a raw_ostream for standard error.
253/// Use it like: errs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000254raw_ostream &llvm::errs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000255 static raw_stderr_ostream S;
256 return S;
257}
258
259//===----------------------------------------------------------------------===//
260// raw_os_ostream
261//===----------------------------------------------------------------------===//
262
Chris Lattner944fac72008-08-23 22:23:09 +0000263raw_os_ostream::~raw_os_ostream() {
264 flush();
265}
266
Chris Lattner07f51f72008-08-17 04:13:37 +0000267/// flush_impl - The is the piece of the class that is implemented by
268/// subclasses. This outputs the currently buffered data and resets the
269/// buffer to empty.
270void raw_os_ostream::flush_impl() {
271 if (OutBufCur-OutBufStart)
272 OS.write(OutBufStart, OutBufCur-OutBufStart);
273 HandleFlush();
274}
Chris Lattner78a28122008-08-23 22:43:04 +0000275
276//===----------------------------------------------------------------------===//
277// raw_string_ostream
278//===----------------------------------------------------------------------===//
279
280raw_string_ostream::~raw_string_ostream() {
281 flush();
282}
283
284/// flush_impl - The is the piece of the class that is implemented by
285/// subclasses. This outputs the currently buffered data and resets the
286/// buffer to empty.
287void raw_string_ostream::flush_impl() {
288 if (OutBufCur-OutBufStart)
289 OS.append(OutBufStart, OutBufCur-OutBufStart);
290 HandleFlush();
291}
292
293//===----------------------------------------------------------------------===//
294// raw_svector_ostream
295//===----------------------------------------------------------------------===//
296
297raw_svector_ostream::~raw_svector_ostream() {
298 flush();
299}
300
301/// flush_impl - The is the piece of the class that is implemented by
302/// subclasses. This outputs the currently buffered data and resets the
303/// buffer to empty.
304void raw_svector_ostream::flush_impl() {
305 if (OutBufCur-OutBufStart)
306 OS.append(OutBufStart, OutBufCur);
307 HandleFlush();
308}
309