text: // Copyright 2006-2008 the V8 project authors. All rights reserved.
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  //       notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  //       copyright notice, this list of conditions and the following
  //       disclaimer in the documentation and/or other materials provided
  //       with the distribution.
  //     * Neither the name of Google Inc. nor the names of its
  //       contributors may be used to endorse or promote products derived
  //       from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  #include <stdarg.h>
  
  #include "v8.h"
  
  #include "platform.h"
  
  #include "sys/stat.h"
  
  namespace v8 { namespace internal {
  
  
  // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
  // figure 3-3, page 48, where the function is called clp2.
  uint32_t RoundUpToPowerOf2(uint32_t x) {
    x = x - 1;
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >> 16);
    return x + 1;
  }
  
  
  byte* EncodeInt(byte* p, int x) {
    while (x < -64 || x >= 64) {
      *p++ = static_cast<byte>(x & 127);
      x = ArithmeticShiftRight(x, 7);
    }
    // -64 <= x && x < 64
    *p++ = static_cast<byte>(x + 192);
    return p;
  }
  
  
  byte* DecodeInt(byte* p, int* x) {
    int r = 0;
    unsigned int s = 0;
    byte b = *p++;
    while (b < 128) {
      r |= static_cast<int>(b) << s;
      s += 7;
      b = *p++;
    }
    // b >= 128
    *x = r | ((static_cast<int>(b) - 192) << s);
    return p;
  }
  
  
  byte* EncodeUnsignedIntBackward(byte* p, unsigned int x) {
    while (x >= 128) {
      *--p = static_cast<byte>(x & 127);
      x = x >> 7;
    }
    // x < 128
    *--p = static_cast<byte>(x + 128);
    return p;
  }
  
  
  void PrintF(const char* format, ...) {
    va_list arguments;
    va_start(arguments, format);
    OS::VPrint(format, arguments);
    va_end(arguments);
  }
  
  
  void Flush() {
    fflush(stdout);
  }
  
  
  char* ReadLine(const char* prompt) {
    char* result = NULL;
    char line_buf[256];
    int offset = 0;
    bool keep_going = true;
    fprintf(stdout, "%s", prompt);
    fflush(stdout);
    while (keep_going) {
      if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
        // fgets got an error. Just give up.
        if (result != NULL) {
          DeleteArray(result);
        }
        return NULL;
      }
      int len = strlen(line_buf);
      if (len > 1 &&
          line_buf[len - 2] == '\\' &&
          line_buf[len - 1] == '\n') {
        // When we read a line that ends with a "\" we remove the escape and
        // append the remainder.
        line_buf[len - 2] = '\n';
        line_buf[len - 1] = 0;
        len -= 1;
      } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
        // Since we read a new line we are done reading the line. This
        // will exit the loop after copying this buffer into the result.
        keep_going = false;
      }
      if (result == NULL) {
        // Allocate the initial result and make room for the terminating '\0'
        result = NewArray<char>(len + 1);
      } else {
        // Allocate a new result with enough room for the new addition.
        int new_len = offset + len + 1;
        char* new_result = NewArray<char>(new_len);
        // Copy the existing input into the new array and set the new
        // array as the result.
        memcpy(new_result, result, offset * kCharSize);
        DeleteArray(result);
        result = new_result;
      }
      // Copy the newly read line into the result.
      memcpy(result + offset, line_buf, len * kCharSize);
      offset += len;
    }
    ASSERT(result != NULL);
    result[offset] = '\0';
    return result;
  }
  
  
  char* ReadCharsFromFile(const char* filename,
                          int* size,
                          int extra_space,
                          bool verbose) {
    FILE* file = OS::FOpen(filename, "rb");
    if (file == NULL || fseek(file, 0, SEEK_END) != 0) {
      if (verbose) {
        OS::PrintError("Cannot read from file %s.\n", filename);
      }
      return NULL;
    }
  
    // Get the size of the file and rewind it.
    *size = ftell(file);
    rewind(file);
  
    char* result = NewArray<char>(*size + extra_space);
    for (int i = 0; i < *size;) {
      int read = fread(&result[i], 1, *size - i, file);
      if (read <= 0) {
        fclose(file);
        DeleteArray(result);
        return NULL;
      }
      i += read;
    }
    fclose(file);
    return result;
  }
  
  
  char* ReadChars(const char* filename, int* size, bool verbose) {
    return ReadCharsFromFile(filename, size, 0, verbose);
  }
  
  
  Vector<const char> ReadFile(const char* filename,
                              bool* exists,
                              bool verbose) {
    int size;
    char* result = ReadCharsFromFile(filename, &size, 1, verbose);
    if (!result) {
      *exists = false;
      return Vector<const char>::empty();
    }
    result[size] = '\0';
    *exists = true;
    return Vector<const char>(result, size);
  }
  
  
  int WriteCharsToFile(const char* str, int size, FILE* f) {
    int total = 0;
    while (total < size) {
      int write = fwrite(str, 1, size - total, f);
      if (write == 0) {
        return total;
      }
      total += write;
      str += write;
    }
    return total;
  }
  
  
  int WriteChars(const char* filename,
                 const char* str,
                 int size,
                 bool verbose) {
    FILE* f = OS::FOpen(filename, "wb");
    if (f == NULL) {
      if (verbose) {
        OS::PrintError("Cannot open file %s for reading.\n", filename);
      }
      return 0;
    }
    int written = WriteCharsToFile(str, size, f);
    fclose(f);
    return written;
  }
  
  
  StringBuilder::StringBuilder(int size) {
    buffer_ = Vector<char>::New(size);
    position_ = 0;
  }
  
  
  void StringBuilder::AddString(const char* s) {
    AddSubstring(s, strlen(s));
  }
  
  
  void StringBuilder::AddSubstring(const char* s, int n) {
    ASSERT(!is_finalized() && position_ + n < buffer_.length());
    ASSERT(static_cast<size_t>(n) <= strlen(s));
    memcpy(&buffer_[position_], s, n * kCharSize);
    position_ += n;
  }
  
  
  void StringBuilder::AddFormatted(const char* format, ...) {
    ASSERT(!is_finalized() && position_ < buffer_.length());
    va_list args;
    va_start(args, format);
    int n = OS::VSNPrintF(buffer_ + position_, format, args);
    va_end(args);
    if (n < 0 || n >= (buffer_.length() - position_)) {
      position_ = buffer_.length();
    } else {
      position_ += n;
    }
  }
  
  
  void StringBuilder::AddPadding(char c, int count) {
    for (int i = 0; i < count; i++) {
      AddCharacter(c);
    }
  }
  
  
  char* StringBuilder::Finalize() {
    ASSERT(!is_finalized() && position_ < buffer_.length());
    buffer_[position_] = '\0';
    // Make sure nobody managed to add a 0-character to the
    // buffer while building the string.
    ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
    position_ = -1;
    ASSERT(is_finalized());
    return buffer_.start();
  }
  
  } }  // namespace v8::internal
  