raw_ostream: Replace flush_impl with write_impl, which takes data to
[oota-llvm.git] / lib / Support / raw_ostream.cpp
1 //===--- 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"
15 #include "llvm/Support/Format.h"
16 #include "llvm/System/Program.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/Config/config.h"
19 #include <ostream>
20
21 #if defined(HAVE_UNISTD_H)
22 # include <unistd.h>
23 #endif
24 #if defined(HAVE_FCNTL_H)
25 # include <fcntl.h>
26 #endif
27
28 #if defined(_MSC_VER)
29 #include <io.h>
30 #include <fcntl.h>
31 #ifndef STDIN_FILENO
32 # define STDIN_FILENO 0
33 #endif
34 #ifndef STDOUT_FILENO
35 # define STDOUT_FILENO 1
36 #endif
37 #ifndef STDERR_FILENO
38 # define STDERR_FILENO 2
39 #endif
40 #endif
41
42 using namespace llvm;
43
44
45 // An out of line virtual method to provide a home for the class vtable.
46 void raw_ostream::handle() {}
47
48 raw_ostream &raw_ostream::operator<<(unsigned long N) {
49   // Zero is a special case.
50   if (N == 0)
51     return *this << '0';
52   
53   char NumberBuffer[20];
54   char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
55   char *CurPtr = EndPtr;
56   
57   while (N) {
58     *--CurPtr = '0' + char(N % 10);
59     N /= 10;
60   }
61   return write(CurPtr, EndPtr-CurPtr);
62 }
63
64 raw_ostream &raw_ostream::operator<<(long N) {
65   if (N <  0) {
66     *this << '-';
67     N = -N;
68   }
69   
70   return this->operator<<(static_cast<unsigned long>(N));
71 }
72
73 raw_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
89 raw_ostream &raw_ostream::operator<<(long long N) {
90   if (N <  0) {
91     *this << '-';
92     N = -N;
93   }
94   
95   return this->operator<<(static_cast<unsigned long long>(N));
96 }
97
98 raw_ostream &raw_ostream::operator<<(const void *P) {
99   uintptr_t N = (uintptr_t) P;
100   *this << '0' << 'x';
101   
102   // Zero is a special case.
103   if (N == 0)
104     return *this << '0';
105
106   char NumberBuffer[20];
107   char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
108   char *CurPtr = EndPtr;
109
110   while (N) {
111     unsigned x = N % 16;
112     *--CurPtr = (x < 10 ? '0' + x : 'a' + x - 10);
113     N /= 16;
114   }
115
116   return write(CurPtr, EndPtr-CurPtr);
117 }
118
119 void raw_ostream::flush_nonempty() {
120   assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
121   write_impl(OutBufStart, OutBufCur - OutBufStart);
122   OutBufCur = OutBufStart;    
123 }
124
125 raw_ostream &raw_ostream::write(unsigned char C) {
126   if (!OutBufStart)
127     SetBufferSize(4096);
128   else if (OutBufCur >= OutBufEnd)
129     flush_nonempty();
130
131   *OutBufCur++ = C;
132   return *this;
133 }
134
135 raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
136   if (!OutBufStart)
137     SetBufferSize(4096);
138   else if (OutBufCur+Size > OutBufEnd)
139     flush_nonempty();
140   
141   // Handle short strings specially, memcpy isn't very good at very short
142   // strings.
143   switch (Size) {
144   case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
145   case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
146   case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
147   case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
148   case 0: break;
149   default:
150     // Normally the string to emit is shorter than the buffer.
151     if (Size <= unsigned(OutBufEnd-OutBufStart)) {
152       memcpy(OutBufCur, Ptr, Size);
153       break;
154     } 
155
156     // Otherwise we are emitting a string larger than our buffer. We
157     // know we already flushed, so just write it out directly.
158     write_impl(Ptr, Size);
159     Size = 0;
160     break;
161   }
162   OutBufCur += Size;
163
164   if (Unbuffered)
165     flush();
166   return *this;
167 }
168
169 // Formatted output.
170 raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
171   // If we have more than a few bytes left in our output buffer, try formatting
172   // directly onto its end.
173   unsigned NextBufferSize = 127;
174   if (OutBufEnd-OutBufCur > 3) {
175     unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
176     unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
177     
178     // Common case is that we have plenty of space.
179     if (BytesUsed < BufferBytesLeft) {
180       OutBufCur += BytesUsed;
181       return *this;
182     }
183     
184     // Otherwise, we overflowed and the return value tells us the size to try
185     // again with.
186     NextBufferSize = BytesUsed;
187   }
188   
189   // If we got here, we didn't have enough space in the output buffer for the
190   // string.  Try printing into a SmallVector that is resized to have enough
191   // space.  Iterate until we win.
192   SmallVector<char, 128> V;
193   
194   while (1) {
195     V.resize(NextBufferSize);
196     
197     // Try formatting into the SmallVector.
198     unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
199     
200     // If BytesUsed fit into the vector, we win.
201     if (BytesUsed <= NextBufferSize)
202       return write(&V[0], BytesUsed);
203     
204     // Otherwise, try again with a new size.
205     assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
206     NextBufferSize = BytesUsed;
207   }
208 }
209
210 //===----------------------------------------------------------------------===//
211 //  Formatted Output
212 //===----------------------------------------------------------------------===//
213
214 // Out of line virtual method.
215 void format_object_base::home() {
216 }
217
218 //===----------------------------------------------------------------------===//
219 //  raw_fd_ostream
220 //===----------------------------------------------------------------------===//
221
222 /// raw_fd_ostream - Open the specified file for writing. If an error
223 /// occurs, information about the error is put into ErrorInfo, and the
224 /// stream should be immediately destroyed; the string will be empty
225 /// if no error occurred.
226 raw_fd_ostream::raw_fd_ostream(const char *Filename, bool Binary,
227                                std::string &ErrorInfo) : pos(0) {
228   ErrorInfo.clear();
229
230   // Handle "-" as stdout.
231   if (Filename[0] == '-' && Filename[1] == 0) {
232     FD = STDOUT_FILENO;
233     // If user requested binary then put stdout into binary mode if
234     // possible.
235     if (Binary)
236       sys::Program::ChangeStdoutToBinary();
237     ShouldClose = false;
238     return;
239   }
240   
241   int Flags = O_WRONLY|O_CREAT|O_TRUNC;
242 #ifdef O_BINARY
243   if (Binary)
244     Flags |= O_BINARY;
245 #endif
246   FD = open(Filename, Flags, 0644);
247   if (FD < 0) {
248     ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
249     ShouldClose = false;
250   } else {
251     ShouldClose = true;
252   }
253 }
254
255 raw_fd_ostream::~raw_fd_ostream() {
256   if (FD >= 0) {
257     flush();
258     if (ShouldClose)
259       ::close(FD);
260   }
261 }
262
263 void raw_fd_ostream::write_impl(const char *Ptr, unsigned Size) {
264   assert (FD >= 0 && "File already closed.");
265   pos += Size;
266   ::write(FD, Ptr, Size);
267 }
268
269 void raw_fd_ostream::close() {
270   assert (ShouldClose);
271   ShouldClose = false;
272   flush();
273   ::close(FD);
274   FD = -1;
275 }
276
277 uint64_t raw_fd_ostream::seek(uint64_t off) {
278   flush();
279   pos = lseek(FD, off, SEEK_SET);
280   return pos;  
281 }
282
283 //===----------------------------------------------------------------------===//
284 //  raw_stdout/err_ostream
285 //===----------------------------------------------------------------------===//
286
287 raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {}
288 raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false, 
289                                                         true) {}
290
291 // An out of line virtual method to provide a home for the class vtable.
292 void raw_stdout_ostream::handle() {}
293 void raw_stderr_ostream::handle() {}
294
295 /// outs() - This returns a reference to a raw_ostream for standard output.
296 /// Use it like: outs() << "foo" << "bar";
297 raw_ostream &llvm::outs() {
298   static raw_stdout_ostream S;
299   return S;
300 }
301
302 /// errs() - This returns a reference to a raw_ostream for standard error.
303 /// Use it like: errs() << "foo" << "bar";
304 raw_ostream &llvm::errs() {
305   static raw_stderr_ostream S;
306   return S;
307 }
308
309 //===----------------------------------------------------------------------===//
310 //  raw_os_ostream
311 //===----------------------------------------------------------------------===//
312
313 raw_os_ostream::~raw_os_ostream() {
314   flush();
315 }
316
317 void raw_os_ostream::write_impl(const char *Ptr, unsigned Size) {
318   OS.write(Ptr, Size);
319 }
320
321 //===----------------------------------------------------------------------===//
322 //  raw_string_ostream
323 //===----------------------------------------------------------------------===//
324
325 raw_string_ostream::~raw_string_ostream() {
326   flush();
327 }
328
329 void raw_string_ostream::write_impl(const char *Ptr, unsigned Size) {
330   OS.append(Ptr, Size);
331 }
332
333 //===----------------------------------------------------------------------===//
334 //  raw_svector_ostream
335 //===----------------------------------------------------------------------===//
336
337 raw_svector_ostream::~raw_svector_ostream() {
338   flush();
339 }
340
341 void raw_svector_ostream::write_impl(const char *Ptr, unsigned Size) {
342   OS.append(Ptr, Ptr + Size);
343 }
344