1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdarg.h> 29 30 #include "v8.h" 31 32 #include "platform.h" 33 34 #include "sys/stat.h" 35 36 namespace v8 { 37 namespace internal { 38 39 40 void PrintF(const char* format, ...) { 41 va_list arguments; 42 va_start(arguments, format); 43 OS::VPrint(format, arguments); 44 va_end(arguments); 45 } 46 47 48 void PrintF(FILE* out, const char* format, ...) { 49 va_list arguments; 50 va_start(arguments, format); 51 OS::VFPrint(out, format, arguments); 52 va_end(arguments); 53 } 54 55 56 void Flush(FILE* out) { 57 fflush(out); 58 } 59 60 61 char* ReadLine(const char* prompt) { 62 char* result = NULL; 63 char line_buf[256]; 64 int offset = 0; 65 bool keep_going = true; 66 fprintf(stdout, "%s", prompt); 67 fflush(stdout); 68 while (keep_going) { 69 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { 70 // fgets got an error. Just give up. 71 if (result != NULL) { 72 DeleteArray(result); 73 } 74 return NULL; 75 } 76 int len = StrLength(line_buf); 77 if (len > 1 && 78 line_buf[len - 2] == '\\' && 79 line_buf[len - 1] == '\n') { 80 // When we read a line that ends with a "\" we remove the escape and 81 // append the remainder. 82 line_buf[len - 2] = '\n'; 83 line_buf[len - 1] = 0; 84 len -= 1; 85 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { 86 // Since we read a new line we are done reading the line. This 87 // will exit the loop after copying this buffer into the result. 88 keep_going = false; 89 } 90 if (result == NULL) { 91 // Allocate the initial result and make room for the terminating '\0' 92 result = NewArray<char>(len + 1); 93 } else { 94 // Allocate a new result with enough room for the new addition. 95 int new_len = offset + len + 1; 96 char* new_result = NewArray<char>(new_len); 97 // Copy the existing input into the new array and set the new 98 // array as the result. 99 memcpy(new_result, result, offset * kCharSize); 100 DeleteArray(result); 101 result = new_result; 102 } 103 // Copy the newly read line into the result. 104 memcpy(result + offset, line_buf, len * kCharSize); 105 offset += len; 106 } 107 ASSERT(result != NULL); 108 result[offset] = '\0'; 109 return result; 110 } 111 112 113 char* ReadCharsFromFile(const char* filename, 114 int* size, 115 int extra_space, 116 bool verbose) { 117 FILE* file = OS::FOpen(filename, "rb"); 118 if (file == NULL || fseek(file, 0, SEEK_END) != 0) { 119 if (verbose) { 120 OS::PrintError("Cannot read from file %s.\n", filename); 121 } 122 return NULL; 123 } 124 125 // Get the size of the file and rewind it. 126 *size = ftell(file); 127 rewind(file); 128 129 char* result = NewArray<char>(*size + extra_space); 130 for (int i = 0; i < *size;) { 131 int read = static_cast<int>(fread(&result[i], 1, *size - i, file)); 132 if (read <= 0) { 133 fclose(file); 134 DeleteArray(result); 135 return NULL; 136 } 137 i += read; 138 } 139 fclose(file); 140 return result; 141 } 142 143 144 byte* ReadBytes(const char* filename, int* size, bool verbose) { 145 char* chars = ReadCharsFromFile(filename, size, 0, verbose); 146 return reinterpret_cast<byte*>(chars); 147 } 148 149 150 Vector<const char> ReadFile(const char* filename, 151 bool* exists, 152 bool verbose) { 153 int size; 154 char* result = ReadCharsFromFile(filename, &size, 1, verbose); 155 if (!result) { 156 *exists = false; 157 return Vector<const char>::empty(); 158 } 159 result[size] = '\0'; 160 *exists = true; 161 return Vector<const char>(result, size); 162 } 163 164 165 int WriteCharsToFile(const char* str, int size, FILE* f) { 166 int total = 0; 167 while (total < size) { 168 int write = static_cast<int>(fwrite(str, 1, size - total, f)); 169 if (write == 0) { 170 return total; 171 } 172 total += write; 173 str += write; 174 } 175 return total; 176 } 177 178 179 int AppendChars(const char* filename, 180 const char* str, 181 int size, 182 bool verbose) { 183 FILE* f = OS::FOpen(filename, "ab"); 184 if (f == NULL) { 185 if (verbose) { 186 OS::PrintError("Cannot open file %s for writing.\n", filename); 187 } 188 return 0; 189 } 190 int written = WriteCharsToFile(str, size, f); 191 fclose(f); 192 return written; 193 } 194 195 196 int WriteChars(const char* filename, 197 const char* str, 198 int size, 199 bool verbose) { 200 FILE* f = OS::FOpen(filename, "wb"); 201 if (f == NULL) { 202 if (verbose) { 203 OS::PrintError("Cannot open file %s for writing.\n", filename); 204 } 205 return 0; 206 } 207 int written = WriteCharsToFile(str, size, f); 208 fclose(f); 209 return written; 210 } 211 212 213 int WriteBytes(const char* filename, 214 const byte* bytes, 215 int size, 216 bool verbose) { 217 const char* str = reinterpret_cast<const char*>(bytes); 218 return WriteChars(filename, str, size, verbose); 219 } 220 221 222 StringBuilder::StringBuilder(int size) { 223 buffer_ = Vector<char>::New(size); 224 position_ = 0; 225 } 226 227 228 void StringBuilder::AddString(const char* s) { 229 AddSubstring(s, StrLength(s)); 230 } 231 232 233 void StringBuilder::AddSubstring(const char* s, int n) { 234 ASSERT(!is_finalized() && position_ + n < buffer_.length()); 235 ASSERT(static_cast<size_t>(n) <= strlen(s)); 236 memcpy(&buffer_[position_], s, n * kCharSize); 237 position_ += n; 238 } 239 240 241 void StringBuilder::AddFormatted(const char* format, ...) { 242 va_list arguments; 243 va_start(arguments, format); 244 AddFormattedList(format, arguments); 245 va_end(arguments); 246 } 247 248 249 void StringBuilder::AddFormattedList(const char* format, va_list list) { 250 ASSERT(!is_finalized() && position_ < buffer_.length()); 251 int n = OS::VSNPrintF(buffer_ + position_, format, list); 252 if (n < 0 || n >= (buffer_.length() - position_)) { 253 position_ = buffer_.length(); 254 } else { 255 position_ += n; 256 } 257 } 258 259 260 void StringBuilder::AddPadding(char c, int count) { 261 for (int i = 0; i < count; i++) { 262 AddCharacter(c); 263 } 264 } 265 266 267 char* StringBuilder::Finalize() { 268 ASSERT(!is_finalized() && position_ < buffer_.length()); 269 buffer_[position_] = '\0'; 270 // Make sure nobody managed to add a 0-character to the 271 // buffer while building the string. 272 ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_)); 273 position_ = -1; 274 ASSERT(is_finalized()); 275 return buffer_.start(); 276 } 277 278 279 MemoryMappedExternalResource::MemoryMappedExternalResource(const char* filename) 280 : filename_(NULL), 281 data_(NULL), 282 length_(0), 283 remove_file_on_cleanup_(false) { 284 Init(filename); 285 } 286 287 288 MemoryMappedExternalResource:: 289 MemoryMappedExternalResource(const char* filename, 290 bool remove_file_on_cleanup) 291 : filename_(NULL), 292 data_(NULL), 293 length_(0), 294 remove_file_on_cleanup_(remove_file_on_cleanup) { 295 Init(filename); 296 } 297 298 299 MemoryMappedExternalResource::~MemoryMappedExternalResource() { 300 // Release the resources if we had successfully acquired them: 301 if (file_ != NULL) { 302 delete file_; 303 if (remove_file_on_cleanup_) { 304 OS::Remove(filename_); 305 } 306 DeleteArray<char>(filename_); 307 } 308 } 309 310 311 void MemoryMappedExternalResource::Init(const char* filename) { 312 file_ = OS::MemoryMappedFile::open(filename); 313 if (file_ != NULL) { 314 filename_ = StrDup(filename); 315 data_ = reinterpret_cast<char*>(file_->memory()); 316 length_ = file_->size(); 317 } 318 } 319 320 321 bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const { 322 bool is_ascii = true; 323 324 int line_no = 1; 325 const char* start_of_line = data_; 326 const char* end = data_ + length_; 327 for (const char* p = data_; p < end; p++) { 328 char c = *p; 329 if ((c & 0x80) != 0) { 330 // Non-ascii detected: 331 is_ascii = false; 332 333 // Report the error and abort if appropriate: 334 if (abort_if_failed) { 335 int char_no = static_cast<int>(p - start_of_line) - 1; 336 337 ASSERT(filename_ != NULL); 338 PrintF("\n\n\n" 339 "Abort: Non-Ascii character 0x%.2x in file %s line %d char %d", 340 c, filename_, line_no, char_no); 341 342 // Allow for some context up to kNumberOfLeadingContextChars chars 343 // before the offending non-ascii char to help the user see where 344 // the offending char is. 345 const int kNumberOfLeadingContextChars = 10; 346 const char* err_context = p - kNumberOfLeadingContextChars; 347 if (err_context < data_) { 348 err_context = data_; 349 } 350 // Compute the length of the error context and print it. 351 int err_context_length = static_cast<int>(p - err_context); 352 if (err_context_length != 0) { 353 PrintF(" after \"%.*s\"", err_context_length, err_context); 354 } 355 PrintF(".\n\n\n"); 356 OS::Abort(); 357 } 358 359 break; // Non-ascii detected. No need to continue scanning. 360 } 361 if (c == '\n') { 362 start_of_line = p; 363 line_no++; 364 } 365 } 366 367 return is_ascii; 368 } 369 370 371 } } // namespace v8::internal 372