add #include
[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/ADT/SmallVector.h"
17 #include "llvm/Config/config.h"
18 #include <ostream>
19
20 #if defined(HAVE_UNISTD_H)
21 # include <unistd.h>
22 #endif
23 #if defined(HAVE_FCNTL_H)
24 # include <fcntl.h>
25 #endif
26
27 #if defined(_MSC_VER)
28 #include <io.h>
29 #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
38 #endif
39
40 using namespace llvm;
41
42
43 // An out of line virtual method to provide a home for the class vtable.
44 void raw_ostream::handle() {}
45
46 raw_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
62 raw_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
74 raw_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
90 raw_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
102 raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
103   if (OutBufCur+Size > OutBufEnd)
104     flush_impl();
105   
106   // Handle short strings specially, memcpy isn't very good at very short
107   // strings.
108   switch (Size) {
109   case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
110   case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
111   case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
112   case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
113   case 0: break;
114   default:
115     // Normally the string to emit is shorter than the buffer.
116     if (Size <= unsigned(OutBufEnd-OutBufStart)) {
117       memcpy(OutBufCur, Ptr, Size);
118       break;
119     }
120
121     // If emitting a string larger than our buffer, emit in chunks.  In this
122     // case we know that we just flushed the buffer.
123     while (Size) {
124       unsigned NumToEmit = OutBufEnd-OutBufStart;
125       if (Size < NumToEmit) NumToEmit = Size;
126       assert(OutBufCur == OutBufStart);
127       memcpy(OutBufStart, Ptr, NumToEmit);
128       Ptr += NumToEmit;
129       Size -= NumToEmit;
130       OutBufCur = OutBufStart + NumToEmit;
131       flush_impl();
132     }
133     break;
134   }
135   OutBufCur += Size;
136   return *this;
137 }
138
139 // Formatted output.
140 raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
141   // If we have more than a few bytes left in our output buffer, try formatting
142   // directly onto its end.
143   unsigned NextBufferSize = 127;
144   if (OutBufEnd-OutBufCur > 3) {
145     unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
146     unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
147     
148     // Common case is that we have plenty of space.
149     if (BytesUsed < BufferBytesLeft) {
150       OutBufCur += BytesUsed;
151       return *this;
152     }
153     
154     // Otherwise, we overflowed and the return value tells us the size to try
155     // again with.
156     NextBufferSize = BytesUsed;
157   }
158   
159   // If we got here, we didn't have enough space in the output buffer for the
160   // string.  Try printing into a SmallVector that is resized to have enough
161   // space.  Iterate until we win.
162   SmallVector<char, 128> V;
163   
164   while (1) {
165     V.resize(NextBufferSize);
166     
167     // Try formatting into the SmallVector.
168     unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
169     
170     // If BytesUsed fit into the vector, we win.
171     if (BytesUsed < NextBufferSize)
172       return write(&V[0], BytesUsed);
173     
174     // Otherwise, try again with a new size.
175     assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
176     NextBufferSize = BytesUsed;
177   }
178 }
179
180 //===----------------------------------------------------------------------===//
181 //  Formatted Output
182 //===----------------------------------------------------------------------===//
183
184 // Out of line virtual method.
185 void format_object_base::home() {
186 }
187
188 //===----------------------------------------------------------------------===//
189 //  raw_fd_ostream
190 //===----------------------------------------------------------------------===//
191
192 /// raw_fd_ostream - Open the specified file for writing.  If an error occurs,
193 /// information about the error is put into ErrorInfo, and the stream should
194 /// be immediately destroyed.
195 raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo) {
196   // Handle "-" as stdout.
197   if (Filename[0] == '-' && Filename[1] == 0) {
198     FD = STDOUT_FILENO;
199     ShouldClose = false;
200     return;
201   }
202   
203   FD = open(Filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
204   if (FD < 0) {
205     ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
206     ShouldClose = false;
207   } else {
208     ShouldClose = true;
209   }
210 }
211
212 raw_fd_ostream::~raw_fd_ostream() {
213   flush();
214   if (ShouldClose)
215     close(FD);
216 }
217
218 void raw_fd_ostream::flush_impl() {
219   if (OutBufCur-OutBufStart)
220     ::write(FD, OutBufStart, OutBufCur-OutBufStart);
221   HandleFlush();
222 }
223
224 //===----------------------------------------------------------------------===//
225 //  raw_stdout/err_ostream
226 //===----------------------------------------------------------------------===//
227
228 raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {}
229 raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false) {}
230
231 // An out of line virtual method to provide a home for the class vtable.
232 void raw_stdout_ostream::handle() {}
233 void raw_stderr_ostream::handle() {}
234
235 /// outs() - This returns a reference to a raw_ostream for standard output.
236 /// Use it like: outs() << "foo" << "bar";
237 raw_ostream &llvm::outs() {
238   static raw_stdout_ostream S;
239   return S;
240 }
241
242 /// errs() - This returns a reference to a raw_ostream for standard error.
243 /// Use it like: errs() << "foo" << "bar";
244 raw_ostream &llvm::errs() {
245   static raw_stderr_ostream S;
246   return S;
247 }
248
249 //===----------------------------------------------------------------------===//
250 //  raw_os_ostream
251 //===----------------------------------------------------------------------===//
252
253 /// flush_impl - The is the piece of the class that is implemented by
254 /// subclasses.  This outputs the currently buffered data and resets the
255 /// buffer to empty.
256 void raw_os_ostream::flush_impl() {
257   if (OutBufCur-OutBufStart)
258     OS.write(OutBufStart, OutBufCur-OutBufStart);
259   HandleFlush();
260 }