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