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