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