<commit_before>#include "vm.hpp"
#include "vm/object_utils.hpp"

#include "builtin/array.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/io.hpp"
#include "objectmemory.hpp"
#include "primitives.hpp"

#include "capi/capi.hpp"
#include "capi/include/ruby.h"

#include <fcntl.h>

using namespace rubinius;
using namespace rubinius::capi;

namespace rubinius {
  namespace capi {

    IO* capi_get_io(NativeMethodEnvironment* env, VALUE io_handle) {
      Handle* handle = Handle::from(io_handle);
      handle->flush(env);
      env->check_tracked_handle(handle, false);
      return c_as<IO>(handle->object());
    }

    static const char* flags_modestr(int oflags)
    {
#ifdef O_BINARY
# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
#else
# define MODE_BINARY(a,b) (a)
#endif
      int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
      if (oflags & O_APPEND) {
        if (accmode == O_WRONLY) {
          return MODE_BINARY("a", "ab");
        }
        if (accmode == O_RDWR) {
          return MODE_BINARY("a+", "ab+");
        }
      }
      switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
      case O_RDONLY:
        return MODE_BINARY("r", "rb");
      case O_WRONLY:
        return MODE_BINARY("w", "wb");
      case O_RDWR:
        return MODE_BINARY("r+", "rb+");
      }
      return NULL;
    }

    RIO* Handle::as_rio(NativeMethodEnvironment* env) {
      if(type_ != cRIO) {
        IO* io_obj = c_as<IO>(object());

        RIO* f = new RIO;
        f->handle = as_value();
        f->fd = io_obj->descriptor()->to_native();
        f->f = fdopen(f->fd, flags_modestr(io_obj->mode()->to_native()));
        // Disable all buffering so that it doesn't get out of sync with
        // the normal IO buffer.
        setvbuf(f->f, 0, _IONBF, 0);

        type_ = cRIO;
        as_.rio = f;
      }

      return as_.rio;
    }
  }
}
extern "C" {
  struct RIO* capi_rio_struct(VALUE io_handle) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();
    return Handle::from(io_handle)->as_rio(env);
  }

  void rb_eof_error() {
    rb_raise(rb_eEOFError, "end of file reached");
  }

  VALUE rb_io_write(VALUE io, VALUE str) {
    return rb_funcall(io, rb_intern("write"), 1, str);
  }

  VALUE rb_io_close(VALUE io) {
    return rb_funcall(io, rb_intern("close"), 0);<commit_msg>Detect a lowlevel C-API IO conversion issue<commit_after>#include "vm.hpp"
#include "vm/object_utils.hpp"

#include "builtin/array.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/io.hpp"
#include "objectmemory.hpp"
#include "primitives.hpp"

#include "capi/capi.hpp"
#include "capi/include/ruby.h"

#include <fcntl.h>

using namespace rubinius;
using namespace rubinius::capi;

namespace rubinius {
  namespace capi {

    IO* capi_get_io(NativeMethodEnvironment* env, VALUE io_handle) {
      Handle* handle = Handle::from(io_handle);
      handle->flush(env);
      env->check_tracked_handle(handle, false);
      return c_as<IO>(handle->object());
    }

    static const char* flags_modestr(int oflags)
    {
#ifdef O_BINARY
# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
#else
# define MODE_BINARY(a,b) (a)
#endif
      int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
      if (oflags & O_APPEND) {
        if (accmode == O_WRONLY) {
          return MODE_BINARY("a", "ab");
        }
        if (accmode == O_RDWR) {
          return MODE_BINARY("a+", "ab+");
        }
      }
      switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
      case O_RDONLY:
        return MODE_BINARY("r", "rb");
      case O_WRONLY:
        return MODE_BINARY("w", "wb");
      case O_RDWR:
        return MODE_BINARY("r+", "rb+");
      }
      return NULL;
    }

    RIO* Handle::as_rio(NativeMethodEnvironment* env) {
      if(type_ != cRIO) {
        IO* io_obj = c_as<IO>(object());

        native_int fd = io_obj->descriptor()->to_native();
        FILE* f = fdopen(fd, flags_modestr(io_obj->mode()->to_native()));

        if(!f) {
          fprintf(stderr, "Error convert fd (%ld) to lowlevel IO: %s (%d)",
              fd, strerror(errno), errno);

          rb_raise(rb_eTypeError,
              "unable to convert fd (%ld) to lowlevel IO: %s (%d)",
              fd, strerror(errno), errno);
        }

        RIO* rf = new RIO;
        rf->handle = as_value();
        rf->fd = fd;
        rf->f = f;

        // Disable all buffering so that it doesn't get out of sync with
        // the normal IO buffer.
        setvbuf(rf->f, 0, _IONBF, 0);

        type_ = cRIO;
        as_.rio = rf;
      }

      return as_.rio;
    }
  }
}
extern "C" {
  struct RIO* capi_rio_struct(VALUE io_handle) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();
    return Handle::from(io_handle)->as_rio(env);
  }

  void rb_eof_error() {
    rb_raise(rb_eEOFError, "end of file reached");
  }

  VALUE rb_io_write(VALUE io, VALUE str) {
    return rb_funcall(io, rb_intern("write"), 1, str);
  }

  VALUE rb_io_close(VALUE io) {
    return rb_funcall(io, rb_intern("close"), 0);
{'fraction_non_alphanumeric': 0.14734539669914495, 'fraction_numerical': 0.0015907735136209981, 'mean_word_length': 2.750932140193885, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7507574', 'n_tokens_mistral': 1887, 'n_tokens_neox': 1847, 'n_words': 399}