Howto make something like Errno::##, for my C ext, or do I need to?

Doesn't rb_sys_fail(0) work for this scenario? I thought if a C
function failed, you could call rb_sys_fail(0) and it would raise the
appropriate Errno. Or am I confused?

Dan

···

-----Original Message-----
From: Charles Mills [mailto:cmills@freeshell.org]
Sent: Wednesday, May 18, 2005 12:20 PM
To: ruby-talk ML
Subject: Re: howto make something like Errno::##, for my C
ext, or do I need to?

Sam Roberts wrote:
> I'm wrapping a library, it returns its errors as numbers (many of
them,
> too many to wrap even automatically), and I don't know how to raise
> exceptions.
>
> I've looked at how ruby deals with unix error numbers. I
guess I could
> cut-n-paste all the code to that my extension does the same...
but
> that seems wrong, somehow.
>
> What I'd really like to do is have only one error class, but raise
> objects as exceptions, with the objects @errno set to the
value, I'd
> do this in ruby like this:
>
> class MyErr < StandardError
> attr_reader :eno
> def initialize(eno); @eno = eno; end
> end
>
>
> ...
> raise MyError.new(35)
>
> Looking at the exception raising APIs in README.EXT, I can't quite
see
> how to do this.
>

In short:
rb_exc_raise(my_err_new(eno));

You probably want to have the ability to add a message to
your error objects so you may want to do:
rb_exc_raise(my_err_new("msg", eno));

or define a function like

static void
raise_my_err(int eno, const char *fmt, ...)
{
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    rb_exc_raise(my_err_new(buf, eno));
}

most of the above is a copy and paste from code in error.c.
I think your new function would look something like this:

static VALUE
my_err_new(const char *buf, int eno)
{
  VALUE self = rb_exc_new2(cMyErr, buf);
  rb_iv_set(self, "@eno", INT2FIX(eno));
  return self;
}

-Charlie

Berger, Daniel wrote:

> From: Charles Mills [mailto:cmills@freeshell.org]
> Sent: Wednesday, May 18, 2005 12:20 PM
> To: ruby-talk ML
> Subject: Re: howto make something like Errno::##, for my C
> ext, or do I need to?
>
>
>
> Sam Roberts wrote:
> > I'm wrapping a library, it returns its errors as numbers (many of
> them,
> > too many to wrap even automatically), and I don't know how to

raise

> > exceptions.
> >
> > I've looked at how ruby deals with unix error numbers. I
> guess I could
> > cut-n-paste all the code to that my extension does the same...
> but
> > that seems wrong, somehow.
> >
> > What I'd really like to do is have only one error class, but

raise

> > objects as exceptions, with the objects @errno set to the
> value, I'd
> > do this in ruby like this:
> >
> > class MyErr < StandardError
> > attr_reader :eno
> > def initialize(eno); @eno = eno; end
> > end
> >
> >
> > ...
> > raise MyError.new(35)
> >
> > Looking at the exception raising APIs in README.EXT, I can't

quite

> see
> > how to do this.
> >
>
> In short:
> rb_exc_raise(my_err_new(eno));
>
> You probably want to have the ability to add a message to
> your error objects so you may want to do:
> rb_exc_raise(my_err_new("msg", eno));
>
> or define a function like
>
> static void
> raise_my_err(int eno, const char *fmt, ...)
> {
> va_list args;
> char buf[BUFSIZ];
>
> va_init_list(args, fmt);
> vsnprintf(buf, BUFSIZ, fmt, args);
> va_end(args);
> rb_exc_raise(my_err_new(buf, eno));
> }
>
> most of the above is a copy and paste from code in error.c.
> I think your new function would look something like this:
>
> static VALUE
> my_err_new(const char *buf, int eno)
> {
> VALUE self = rb_exc_new2(cMyErr, buf);
> rb_iv_set(self, "@eno", INT2FIX(eno));
> return self;
> }
>
> -Charlie

Doesn't rb_sys_fail(0) work for this scenario? I thought if a C
function failed, you could call rb_sys_fail(0) and it would raise the
appropriate Errno. Or am I confused?

Dan

Yeah that works too, if your using the standard library functions. I
thought from the OP that the error numbers he was working with were not
related to those used by the std lib, but I may be wrong.

-Charlie

···

> -----Original Message-----

Thanks for your help, Charlie.

Charlie Mills wrote:

In short:
rb_exc_raise(my_err_new(eno));

Took me a minute to find that... it's in intern.h, can I call those
functions, I mean, should I?

Looking through that code, it seems my only option is to create the
object myself, then call this internal function.

Looks like it will work fine, but is this really recommended?

Daniel wrote:

Doesn't rb_sys_fail(0) work for this scenario? I thought if a C
function failed, you could call rb_sys_fail(0) and it would raise the
appropriate Errno. Or am I confused?

I didn't know about this function, but no, its not for me.

It only makes sense if the C function you are calling is returning a
system error number, i.e. from <errno.h>.

For example, when a C function in our library returns 9, it means "index
out of bounds", but when a system call returns 9 it means bad file
descriptor, and when the Crypoki API (random example) returns 9 it means
CKR_NEED_TO_CREATE_THREADS.

I wouldn't want to return Errno::EBADF from my wrapper when the error is
index out of bounds!

Charlie wrote:

Yeah that works too, if your using the standard library functions. I
thought from the OP that the error numbers he was working with were not
related to those used by the std lib, but I may be wrong.

Nope, bang on.

Sam

···

--

Sam Roberts wrote:

Thanks for your help, Charlie.

Charlie Mills wrote:
> In short:
> rb_exc_raise(my_err_new(eno));

Took me a minute to find that... it's in intern.h, can I call those
functions, I mean, should I?

It is OK to call those... I asked about this once:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/90163
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/1807

Looking through that code, it seems my only option is to create the
object myself, then call this internal function.

Looks like it will work fine, but is this really recommended?

It is fine. You also need to create your error class:
class MyErr < StandardError; end # or in C:
eMyError = rb_define_class("MyError", rb_eStandardError);

Then you can define an accessor in Ruby or in C:
attr_reader :eno
rb_define_attr(eMyError, "eno", 1, 0);

I wouldn't worry about writing an init function if your only going to
be raising these errors from C.

You can instantiate/raise the errors as I described in the earlier
post.

-Charlie

Daniel wrote:
> Doesn't rb_sys_fail(0) work for this scenario? I thought if a C
> function failed, you could call rb_sys_fail(0) and it would raise

the

> appropriate Errno. Or am I confused?

I didn't know about this function, but no, its not for me.

It only makes sense if the C function you are calling is returning a
system error number, i.e. from <errno.h>.

For example, when a C function in our library returns 9, it means

"index

out of bounds", but when a system call returns 9 it means bad file
descriptor, and when the Crypoki API (random example) returns 9 it

means

CKR_NEED_TO_CREATE_THREADS.

I wouldn't want to return Errno::EBADF from my wrapper when the error

is

index out of bounds!

Charlie wrote:
> Yeah that works too, if your using the standard library functions.

I

> thought from the OP that the error numbers he was working with were

not

···

> related to those used by the std lib, but I may be wrong.

Nope, bang on.

Sam

--
http://www.certicom.com

Wrote Charles Mills <cmills@freeshell.org>, on Thu, May 19, 2005 at 07:30:13AM +0900:

Sam Roberts wrote:
> Looks like it will work fine, but is this really recommended?

It is fine. You also need to create your error class:
class MyErr < StandardError; end # or in C:
eMyError = rb_define_class("MyError", rb_eStandardError);

Then you can define an accessor in Ruby or in C:
attr_reader :eno
rb_define_attr(eMyError, "eno", 1, 0);

I wouldn't worry about writing an init function if your only going to
be raising these errors from C.

Worked like a charm, thanks a bunch.

Sam

···

--