blob: b9beac2869aa4e8c118d2b32713a74a8ca0d50aa [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>
Owen Andersoncb371882008-08-21 00:14:44 +000029#ifndef STDIN_FILENO
30# define STDIN_FILENO 0
31#endif
32#ifndef STDOUT_FILENO
33# define STDOUT_FILENO 1
34#endif
35#ifndef STDERR_FILENO
36# define STDERR_FILENO 2
37#endif
Chris Lattner60d39622008-08-17 01:35:29 +000038#endif
39
Chris Lattner969a46a2008-08-22 15:45:00 +000040using namespace llvm;
41
42
Chris Lattner60d39622008-08-17 01:35:29 +000043// An out of line virtual method to provide a home for the class vtable.
44void raw_ostream::handle() {}
45
Owen Anderson66b17ba2008-08-21 20:58:52 +000046raw_ostream &raw_ostream::operator<<(unsigned long N) {
47 // Zero is a special case.
48 if (N == 0)
49 return *this << '0';
50
51 char NumberBuffer[20];
52 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
53 char *CurPtr = EndPtr;
54
55 while (N) {
56 *--CurPtr = '0' + char(N % 10);
57 N /= 10;
58 }
59 return write(CurPtr, EndPtr-CurPtr);
60}
61
62raw_ostream &raw_ostream::operator<<(long N) {
63 if (N < 0) {
64 if (OutBufCur >= OutBufEnd)
65 flush_impl();
66 *OutBufCur++ = '-';
67
68 N = -N;
69 }
70
71 return this->operator<<(static_cast<unsigned long>(N));
72}
73
74raw_ostream &raw_ostream::operator<<(unsigned long long N) {
75 // Zero is a special case.
76 if (N == 0)
77 return *this << '0';
78
79 char NumberBuffer[20];
80 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
81 char *CurPtr = EndPtr;
82
83 while (N) {
84 *--CurPtr = '0' + char(N % 10);
85 N /= 10;
86 }
87 return write(CurPtr, EndPtr-CurPtr);
88}
89
90raw_ostream &raw_ostream::operator<<(long long N) {
91 if (N < 0) {
92 if (OutBufCur >= OutBufEnd)
93 flush_impl();
94 *OutBufCur++ = '-';
95
96 N = -N;
97 }
98
99 return this->operator<<(static_cast<unsigned long long>(N));
100}
101
Chris Lattner944fac72008-08-23 22:23:09 +0000102raw_ostream &raw_ostream::operator<<(const void *P) {
103 // FIXME: This could be much faster if it matters.
104 return *this << format("%p", P);
105}
106
107
Owen Anderson66b17ba2008-08-21 20:58:52 +0000108raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
109 if (OutBufCur+Size > OutBufEnd)
110 flush_impl();
111
112 // Handle short strings specially, memcpy isn't very good at very short
113 // strings.
114 switch (Size) {
115 case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
116 case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
117 case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
118 case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
119 case 0: break;
120 default:
121 // Normally the string to emit is shorter than the buffer.
122 if (Size <= unsigned(OutBufEnd-OutBufStart)) {
123 memcpy(OutBufCur, Ptr, Size);
124 break;
125 }
126
127 // If emitting a string larger than our buffer, emit in chunks. In this
128 // case we know that we just flushed the buffer.
129 while (Size) {
130 unsigned NumToEmit = OutBufEnd-OutBufStart;
131 if (Size < NumToEmit) NumToEmit = Size;
132 assert(OutBufCur == OutBufStart);
133 memcpy(OutBufStart, Ptr, NumToEmit);
134 Ptr += NumToEmit;
Owen Andersonfd2a0532008-08-21 22:39:33 +0000135 Size -= NumToEmit;
Owen Anderson66b17ba2008-08-21 20:58:52 +0000136 OutBufCur = OutBufStart + NumToEmit;
137 flush_impl();
138 }
139 break;
140 }
141 OutBufCur += Size;
142 return *this;
143}
144
Chris Lattner097af7f2008-08-23 19:23:10 +0000145// Formatted output.
146raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
147 // If we have more than a few bytes left in our output buffer, try formatting
148 // directly onto its end.
149 unsigned NextBufferSize = 127;
150 if (OutBufEnd-OutBufCur > 3) {
151 unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
152 unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
153
154 // Common case is that we have plenty of space.
155 if (BytesUsed < BufferBytesLeft) {
156 OutBufCur += BytesUsed;
157 return *this;
158 }
159
160 // Otherwise, we overflowed and the return value tells us the size to try
161 // again with.
162 NextBufferSize = BytesUsed;
163 }
164
165 // If we got here, we didn't have enough space in the output buffer for the
166 // string. Try printing into a SmallVector that is resized to have enough
167 // space. Iterate until we win.
168 SmallVector<char, 128> V;
169
170 while (1) {
171 V.resize(NextBufferSize);
172
173 // Try formatting into the SmallVector.
174 unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
175
176 // If BytesUsed fit into the vector, we win.
177 if (BytesUsed < NextBufferSize)
178 return write(&V[0], BytesUsed);
179
180 // Otherwise, try again with a new size.
181 assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
182 NextBufferSize = BytesUsed;
183 }
184}
185
186//===----------------------------------------------------------------------===//
187// Formatted Output
188//===----------------------------------------------------------------------===//
189
190// Out of line virtual method.
191void format_object_base::home() {
192}
193
Chris Lattner60d39622008-08-17 01:35:29 +0000194//===----------------------------------------------------------------------===//
195// raw_fd_ostream
196//===----------------------------------------------------------------------===//
197
198/// raw_fd_ostream - Open the specified file for writing. If an error occurs,
199/// information about the error is put into ErrorInfo, and the stream should
200/// be immediately destroyed.
201raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo) {
Chris Lattnerc52b1282008-08-17 03:53:23 +0000202 // Handle "-" as stdout.
203 if (Filename[0] == '-' && Filename[1] == 0) {
204 FD = STDOUT_FILENO;
205 ShouldClose = false;
206 return;
207 }
208
Chris Lattner60d39622008-08-17 01:35:29 +0000209 FD = open(Filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
210 if (FD < 0) {
211 ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
212 ShouldClose = false;
213 } else {
214 ShouldClose = true;
215 }
216}
217
218raw_fd_ostream::~raw_fd_ostream() {
219 flush();
220 if (ShouldClose)
221 close(FD);
222}
223
224void raw_fd_ostream::flush_impl() {
225 if (OutBufCur-OutBufStart)
Chris Lattnerd497df52008-08-17 01:46:05 +0000226 ::write(FD, OutBufStart, OutBufCur-OutBufStart);
Chris Lattner60d39622008-08-17 01:35:29 +0000227 HandleFlush();
228}
229
Chris Lattner07f51f72008-08-17 04:13:37 +0000230//===----------------------------------------------------------------------===//
231// raw_stdout/err_ostream
232//===----------------------------------------------------------------------===//
Chris Lattner60d39622008-08-17 01:35:29 +0000233
234raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {}
235raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false) {}
236
237// An out of line virtual method to provide a home for the class vtable.
238void raw_stdout_ostream::handle() {}
239void raw_stderr_ostream::handle() {}
Chris Lattner07f51f72008-08-17 04:13:37 +0000240
241/// outs() - This returns a reference to a raw_ostream for standard output.
242/// Use it like: outs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000243raw_ostream &llvm::outs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000244 static raw_stdout_ostream S;
245 return S;
246}
247
248/// errs() - This returns a reference to a raw_ostream for standard error.
249/// Use it like: errs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000250raw_ostream &llvm::errs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000251 static raw_stderr_ostream S;
252 return S;
253}
254
255//===----------------------------------------------------------------------===//
256// raw_os_ostream
257//===----------------------------------------------------------------------===//
258
Chris Lattner944fac72008-08-23 22:23:09 +0000259raw_os_ostream::~raw_os_ostream() {
260 flush();
261}
262
Chris Lattner07f51f72008-08-17 04:13:37 +0000263/// flush_impl - The is the piece of the class that is implemented by
264/// subclasses. This outputs the currently buffered data and resets the
265/// buffer to empty.
266void raw_os_ostream::flush_impl() {
267 if (OutBufCur-OutBufStart)
268 OS.write(OutBufStart, OutBufCur-OutBufStart);
269 HandleFlush();
270}
Chris Lattner78a28122008-08-23 22:43:04 +0000271
272//===----------------------------------------------------------------------===//
273// raw_string_ostream
274//===----------------------------------------------------------------------===//
275
276raw_string_ostream::~raw_string_ostream() {
277 flush();
278}
279
280/// flush_impl - The is the piece of the class that is implemented by
281/// subclasses. This outputs the currently buffered data and resets the
282/// buffer to empty.
283void raw_string_ostream::flush_impl() {
284 if (OutBufCur-OutBufStart)
285 OS.append(OutBufStart, OutBufCur-OutBufStart);
286 HandleFlush();
287}
288
289//===----------------------------------------------------------------------===//
290// raw_svector_ostream
291//===----------------------------------------------------------------------===//
292
293raw_svector_ostream::~raw_svector_ostream() {
294 flush();
295}
296
297/// flush_impl - The is the piece of the class that is implemented by
298/// subclasses. This outputs the currently buffered data and resets the
299/// buffer to empty.
300void raw_svector_ostream::flush_impl() {
301 if (OutBufCur-OutBufStart)
302 OS.append(OutBufStart, OutBufCur);
303 HandleFlush();
304}
305