Home | History | Annotate | Download | only in src
      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