blob: 104dc771498ae702e49dedc301a26da9e1a1959b [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 Lattner097af7f2008-08-23 19:23:10 +000015#include "llvm/ADT/SmallVector.h"
Chris Lattner969a46a2008-08-22 15:45:00 +000016#include "llvm/Config/config.h"
Chris Lattner07f51f72008-08-17 04:13:37 +000017#include <ostream>
Chris Lattner60d39622008-08-17 01:35:29 +000018
Chris Lattner969a46a2008-08-22 15:45:00 +000019#if defined(HAVE_UNISTD_H)
20# include <unistd.h>
21#endif
22#if defined(HAVE_FCNTL_H)
23# include <fcntl.h>
24#endif
Argyrios Kyrtzidisb68dc362008-08-17 09:25:21 +000025
26#if defined(_MSC_VER)
Chris Lattner60d39622008-08-17 01:35:29 +000027#include <io.h>
Owen Andersoncb371882008-08-21 00:14:44 +000028#ifndef STDIN_FILENO
29# define STDIN_FILENO 0
30#endif
31#ifndef STDOUT_FILENO
32# define STDOUT_FILENO 1
33#endif
34#ifndef STDERR_FILENO
35# define STDERR_FILENO 2
36#endif
Chris Lattner60d39622008-08-17 01:35:29 +000037#endif
38
Chris Lattner969a46a2008-08-22 15:45:00 +000039using namespace llvm;
40
41
Chris Lattner60d39622008-08-17 01:35:29 +000042// An out of line virtual method to provide a home for the class vtable.
43void raw_ostream::handle() {}
44
Owen Anderson66b17ba2008-08-21 20:58:52 +000045raw_ostream &raw_ostream::operator<<(unsigned long N) {
46 // Zero is a special case.
47 if (N == 0)
48 return *this << '0';
49
50 char NumberBuffer[20];
51 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
52 char *CurPtr = EndPtr;
53
54 while (N) {
55 *--CurPtr = '0' + char(N % 10);
56 N /= 10;
57 }
58 return write(CurPtr, EndPtr-CurPtr);
59}
60
61raw_ostream &raw_ostream::operator<<(long N) {
62 if (N < 0) {
63 if (OutBufCur >= OutBufEnd)
64 flush_impl();
65 *OutBufCur++ = '-';
66
67 N = -N;
68 }
69
70 return this->operator<<(static_cast<unsigned long>(N));
71}
72
73raw_ostream &raw_ostream::operator<<(unsigned long long N) {
74 // Zero is a special case.
75 if (N == 0)
76 return *this << '0';
77
78 char NumberBuffer[20];
79 char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
80 char *CurPtr = EndPtr;
81
82 while (N) {
83 *--CurPtr = '0' + char(N % 10);
84 N /= 10;
85 }
86 return write(CurPtr, EndPtr-CurPtr);
87}
88
89raw_ostream &raw_ostream::operator<<(long long N) {
90 if (N < 0) {
91 if (OutBufCur >= OutBufEnd)
92 flush_impl();
93 *OutBufCur++ = '-';
94
95 N = -N;
96 }
97
98 return this->operator<<(static_cast<unsigned long long>(N));
99}
100
101raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
102 if (OutBufCur+Size > OutBufEnd)
103 flush_impl();
104
105 // Handle short strings specially, memcpy isn't very good at very short
106 // strings.
107 switch (Size) {
108 case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
109 case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
110 case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
111 case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
112 case 0: break;
113 default:
114 // Normally the string to emit is shorter than the buffer.
115 if (Size <= unsigned(OutBufEnd-OutBufStart)) {
116 memcpy(OutBufCur, Ptr, Size);
117 break;
118 }
119
120 // If emitting a string larger than our buffer, emit in chunks. In this
121 // case we know that we just flushed the buffer.
122 while (Size) {
123 unsigned NumToEmit = OutBufEnd-OutBufStart;
124 if (Size < NumToEmit) NumToEmit = Size;
125 assert(OutBufCur == OutBufStart);
126 memcpy(OutBufStart, Ptr, NumToEmit);
127 Ptr += NumToEmit;
Owen Andersonfd2a0532008-08-21 22:39:33 +0000128 Size -= NumToEmit;
Owen Anderson66b17ba2008-08-21 20:58:52 +0000129 OutBufCur = OutBufStart + NumToEmit;
130 flush_impl();
131 }
132 break;
133 }
134 OutBufCur += Size;
135 return *this;
136}
137
Chris Lattner097af7f2008-08-23 19:23:10 +0000138// Formatted output.
139raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
140 // If we have more than a few bytes left in our output buffer, try formatting
141 // directly onto its end.
142 unsigned NextBufferSize = 127;
143 if (OutBufEnd-OutBufCur > 3) {
144 unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
145 unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
146
147 // Common case is that we have plenty of space.
148 if (BytesUsed < BufferBytesLeft) {
149 OutBufCur += BytesUsed;
150 return *this;
151 }
152
153 // Otherwise, we overflowed and the return value tells us the size to try
154 // again with.
155 NextBufferSize = BytesUsed;
156 }
157
158 // If we got here, we didn't have enough space in the output buffer for the
159 // string. Try printing into a SmallVector that is resized to have enough
160 // space. Iterate until we win.
161 SmallVector<char, 128> V;
162
163 while (1) {
164 V.resize(NextBufferSize);
165
166 // Try formatting into the SmallVector.
167 unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
168
169 // If BytesUsed fit into the vector, we win.
170 if (BytesUsed < NextBufferSize)
171 return write(&V[0], BytesUsed);
172
173 // Otherwise, try again with a new size.
174 assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
175 NextBufferSize = BytesUsed;
176 }
177}
178
179//===----------------------------------------------------------------------===//
180// Formatted Output
181//===----------------------------------------------------------------------===//
182
183// Out of line virtual method.
184void format_object_base::home() {
185}
186
Chris Lattner60d39622008-08-17 01:35:29 +0000187//===----------------------------------------------------------------------===//
188// raw_fd_ostream
189//===----------------------------------------------------------------------===//
190
191/// raw_fd_ostream - Open the specified file for writing. If an error occurs,
192/// information about the error is put into ErrorInfo, and the stream should
193/// be immediately destroyed.
194raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo) {
Chris Lattnerc52b1282008-08-17 03:53:23 +0000195 // Handle "-" as stdout.
196 if (Filename[0] == '-' && Filename[1] == 0) {
197 FD = STDOUT_FILENO;
198 ShouldClose = false;
199 return;
200 }
201
Chris Lattner60d39622008-08-17 01:35:29 +0000202 FD = open(Filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
203 if (FD < 0) {
204 ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
205 ShouldClose = false;
206 } else {
207 ShouldClose = true;
208 }
209}
210
211raw_fd_ostream::~raw_fd_ostream() {
212 flush();
213 if (ShouldClose)
214 close(FD);
215}
216
217void raw_fd_ostream::flush_impl() {
218 if (OutBufCur-OutBufStart)
Chris Lattnerd497df52008-08-17 01:46:05 +0000219 ::write(FD, OutBufStart, OutBufCur-OutBufStart);
Chris Lattner60d39622008-08-17 01:35:29 +0000220 HandleFlush();
221}
222
Chris Lattner07f51f72008-08-17 04:13:37 +0000223//===----------------------------------------------------------------------===//
224// raw_stdout/err_ostream
225//===----------------------------------------------------------------------===//
Chris Lattner60d39622008-08-17 01:35:29 +0000226
227raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {}
228raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false) {}
229
230// An out of line virtual method to provide a home for the class vtable.
231void raw_stdout_ostream::handle() {}
232void raw_stderr_ostream::handle() {}
Chris Lattner07f51f72008-08-17 04:13:37 +0000233
234/// outs() - This returns a reference to a raw_ostream for standard output.
235/// Use it like: outs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000236raw_ostream &llvm::outs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000237 static raw_stdout_ostream S;
238 return S;
239}
240
241/// errs() - This returns a reference to a raw_ostream for standard error.
242/// Use it like: errs() << "foo" << "bar";
Owen Andersoncb371882008-08-21 00:14:44 +0000243raw_ostream &llvm::errs() {
Chris Lattner07f51f72008-08-17 04:13:37 +0000244 static raw_stderr_ostream S;
245 return S;
246}
247
248//===----------------------------------------------------------------------===//
249// raw_os_ostream
250//===----------------------------------------------------------------------===//
251
252/// flush_impl - The is the piece of the class that is implemented by
253/// subclasses. This outputs the currently buffered data and resets the
254/// buffer to empty.
255void raw_os_ostream::flush_impl() {
256 if (OutBufCur-OutBufStart)
257 OS.write(OutBufStart, OutBufCur-OutBufStart);
258 HandleFlush();
259}