fs_query.c

/* [<][>]
[^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. my_check_is_kind_of
  2. my_get_path_for_dirobj
  3. my_get_path_for_dirent
  4. my_fs_open_query
  5. my_fs_open_live_query
  6. my_open_query
  7. my_read_query
  8. my_get_query
  9. be_query_close
  10. my_init_query
  11. free_query
  12. be_query_s_new
  13. be_query_s_open
  14. be_query_each
  15. be_query_s_foreach
  16. be_query_s_entries
  17. be_query_initialize
  18. be_query_read
  19. be_query_reverse
  20. Init_fs_query

/*
 *  fs_query.c
 */

#include <fs_query.h>
#include "bfs.h"


static VALUE cQuery;


static void
my_check_is_kind_of(VALUE obj, VALUE klass)
/* [<][>][^][v][top][bottom][index][help] */
{
  if (!rb_obj_is_kind_of(obj, klass)) {
    rb_raise(rb_eTypeError,
             "wrong argument type %s (expected %s)",
             rb_class2name(CLASS_OF(obj)), rb_class2name(klass));
  }
}


VALUE
my_get_path_for_dirobj(VALUE dir)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp;
  dirent_t *dp;
  char buf[B_PATH_NAME_LENGTH];
  size_t len = B_PATH_NAME_LENGTH;
  status_t result;

  my_check_is_kind_of(dir, rb_cDir);
  Data_Get_Struct(dir, DIR, dirp);
  my_check_dirp_closed(dirp, "closed directory");

  errno = 0;
  dp = readdir(dirp);
  if (!dp && errno) {
    rb_sys_fail(ROBJ_AS_CSTR(dir));
  }

  result = get_path_for_dirent(dp, buf, len);
  if (result != B_OK) {
    my_sys_fail(result, ROBJ_AS_CSTR(dir));
  }
  return rb_tainted_str_new2(buf);
}


static VALUE
my_get_path_for_dirent(dirent_t *dp)
/* [<][>][^][v][top][bottom][index][help] */
{
  char buf[B_PATH_NAME_LENGTH];
  size_t len = B_PATH_NAME_LENGTH;
  status_t result;

  result = get_path_for_dirent(dp, buf, len);
  if (result != B_OK) {
    my_sys_fail(result, (dp ? dp->d_name:0));
  }
  return rb_tainted_str_new2(buf);
}


static DIR*
my_fs_open_query(VALUE vol, const char *query, uint32 flags)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp;
  dev_t dev;

  rb_secure(2);
  dev = my_get_dev_for_obj(vol);
  dirp = fs_open_query(dev, query, flags);
  if (!dirp) {
    if (errno == EMFILE || errno == ENFILE) {
      rb_gc();
      dirp = fs_open_query(dev, query, flags);
    }
    if (!dirp) {
      rb_sys_fail(query);
    }
  }
  return dirp;
}


static DIR*
my_fs_open_live_query(VALUE vol, const char *query, uint32 flags, port_id port, int32 token)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp;
  dev_t dev;

  rb_secure(2);
  dev = my_get_dev_for_obj(vol);
  dirp = fs_open_live_query(dev, query, flags, port, token);
  if (!dirp) {
    if (errno == EMFILE || errno == ENFILE) {
      rb_gc();
      dirp = fs_open_live_query(dev, query, flags, port, token);
    }
    if (!dirp) {
      rb_sys_fail(query);
    }
  }
  return dirp;
}


static DIR*
my_open_query(int argc, VALUE *argv)
/* [<][>][^][v][top][bottom][index][help] */
{
  VALUE vol, query, flags, port, token;
  uint32 flgs = 0;
  port_id prt = 0;
  int32 tkn = 0;

  rb_scan_args(argc, argv, "23", &vol, &query, &flags, &port, &token);

  Check_SafeStr(query);
  if (argc > 2) {
    flgs = NUM2ULONG(flags);
  }
  if (argc > 3) {
    prt = NUM2LONG(port);
    if (argc > 4) {
      tkn = NUM2LONG(token);
    }
    return my_fs_open_live_query(vol, RSTRING(query)->ptr, flgs, prt, tkn);
  }

  return my_fs_open_query(vol, RSTRING(query)->ptr, flgs);
}


static VALUE
my_read_query(DIR *dirp)
/* [<][>][^][v][top][bottom][index][help] */
{
  dirent_t *dp;

  errno = 0;
  dp = fs_read_query(dirp);
  if (!dp && errno) {
    rb_sys_fail(0);
  }
  if (dp) {
    return my_get_path_for_dirent(dp);
  }
  return Qnil;
}


static DIR*
my_get_query(VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp;

  Data_Get_Struct(qry, DIR, dirp);
  my_check_dirp_closed(dirp, "query closed");
  return dirp;
}


static VALUE
be_query_close(VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp = my_get_query(qry);
  if (fs_close_query(dirp) < 0) {
    rb_sys_fail(ROBJ_AS_CSTR(qry));
  }
  DATA_PTR(qry) = NULL;
  return Qnil;
}


static VALUE
my_init_query(int argc, VALUE *argv, VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  if (DATA_PTR(qry)) {
    be_query_close(qry);
  }
  DATA_PTR(qry) = my_open_query(argc, argv);
  return qry;
}


static void
free_query(DIR *dirp)
/* [<][>][^][v][top][bottom][index][help] */
{
  if (dirp && (fs_close_query(dirp) < 0)) {
    rb_warn("%s", strerror(errno));
  }
}


static VALUE
be_query_s_new(int argc, VALUE *argv, VALUE klass)
/* [<][>][^][v][top][bottom][index][help] */
{
  VALUE obj = Data_Wrap_Struct(klass, 0, free_query, 0);
  rb_obj_call_init(obj, argc, argv);
  return obj;
}


static VALUE
be_query_s_open(int argc, VALUE *argv, VALUE klass)
/* [<][>][^][v][top][bottom][index][help] */
{
  VALUE qry;

  qry = Data_Wrap_Struct(klass, 0, free_query, 0);
  my_init_query(argc, argv, qry);

  if (rb_block_given_p()) {
    return rb_ensure(rb_yield, qry, be_query_close, qry);
  }
  return qry;
}


static VALUE
be_query_each(VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp;
  VALUE path;

  my_check_block_given();
  dirp = my_get_query(qry);

  path = my_read_query(dirp);
  while (!NIL_P(path)) {
    rb_yield(path);
    my_check_dirp_closed(DATA_PTR(qry), "closed query");
    path = my_read_query(dirp);
  }
  return qry;
}


static VALUE
be_query_s_foreach(int argc, VALUE *argv, VALUE klass)
/* [<][>][^][v][top][bottom][index][help] */
{
  VALUE qry = rb_funcall2(cQuery, i_open, argc, argv);
  rb_ensure(be_query_each, qry, be_query_close, qry);
  return Qnil;
}


static VALUE
be_query_s_entries(int argc, VALUE *argv, VALUE klass)
/* [<][>][^][v][top][bottom][index][help] */
{
  VALUE qry = rb_funcall2(cQuery, i_open, argc, argv);
  return rb_ensure(rb_Array, qry, be_query_close, qry);
}


static VALUE
be_query_initialize(int argc, VALUE *argv, VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  if (rb_block_given_p()) {
    char *cname = rb_class2name(CLASS_OF(qry));
    rb_warn("%s::new() does not take block; use %s::open() instead", cname, cname);
  }
  my_init_query(argc, argv, qry);
  return qry;
}


static VALUE
be_query_read(VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  DIR *dirp = my_get_query(qry);
  return my_read_query(dirp);
}


static VALUE
be_query_reverse(VALUE qry)
/* [<][>][^][v][top][bottom][index][help] */
{
  return rb_ary_reverse(rb_Array(qry));
}


void
Init_fs_query()
/* [<][>][^][v][top][bottom][index][help] */
{
  cQuery = rb_define_class_under(mBfs, "Query", rb_cObject);

  rb_include_module(cQuery, rb_mEnumerable);

  rb_define_singleton_method(cQuery, "new", be_query_s_new, -1);
  rb_define_singleton_method(cQuery, "open", be_query_s_open, -1);
  rb_define_singleton_method(cQuery, "foreach", be_query_s_foreach, -1);
  rb_define_singleton_method(cQuery, "entries", be_query_s_entries, -1);

  rb_define_method(cQuery, "initialize", be_query_initialize, -1);
  rb_define_method(cQuery, "read", be_query_read, 0);
  rb_define_method(cQuery, "close", be_query_close, 0);
  rb_define_method(cQuery, "each", be_query_each, 0);
  rb_define_method(cQuery, "reverse", be_query_reverse, 0);

  rb_define_const(mBfs, "LIVE_QUERY", UINT2NUM(B_LIVE_QUERY));
}

/* [<][>][^][v][top][bottom][index][help] */