Forum: Ruby-Gnome 2 [PATCH] Added GString

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Lionel L. (Guest)
on 2009-05-26 04:06
(Received via mailing list)
Hi ruby-gnome2,

For my personnal needs with Ruby GStreamer, I needed to access the
g_string_* stuff in GLib.
Here is a first try to implement the g_string_* stuff in a ruby class.
Please tell me how to improve/add/remove things if necessary, so it
could be integrated as soon as possible.

--
[PATCH] Added GString

Signed-off-by: Lionel L. <removed_email_address@domain.invalid>
---
 glib/src/rbglib.c        |   10 +-
 glib/src/rbglib_string.c |  329
++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 335 insertions(+), 4 deletions(-)
 create mode 100644 glib/src/rbglib_string.c

diff --git a/glib/src/rbglib.c b/glib/src/rbglib.c
index f163e89..e68cbab 100644
--- a/glib/src/rbglib.c
+++ b/glib/src/rbglib.c
@@ -42,6 +42,7 @@ extern void Init_glib_timer();
 extern void Init_glib_unicode();
 extern void Init_glib_keyfile();
 extern void Init_glib_bookmark_file();
+extern void Init_glib_string();

 const gchar *
 rbg_rval_inspect(VALUE object)
@@ -97,14 +98,14 @@ So they occur "cross-thread violation".
 static gpointer
 my_malloc(gsize n_bytes)
 {
-    /* Should we rescue NoMemoryError? */
+    /* Should we rescue NoMemoryError? */
     return ruby_xmalloc(n_bytes);
 }

 static gpointer
 my_realloc(gpointer mem, gsize n_bytes)
 {
-    /* Should we rescue NoMemoryError? */
+    /* Should we rescue NoMemoryError? */
     return ruby_xrealloc(mem, n_bytes);
 }

@@ -162,7 +163,7 @@ rbg_s_os_unix(self)
 #endif
 }

-void
+void
 Init_glib2()
 {
     id_inspect = rb_intern("inspect");
@@ -202,7 +203,7 @@ Init_glib2()
     rb_define_const(mGLib, "MININT", INT2FIX(G_MININT));
     rb_define_const(mGLib, "MAXINT", INT2FIX(G_MAXINT));
     rb_define_const(mGLib, "MAXUINT", INT2FIX(G_MAXUINT));
-
+
     rb_define_const(mGLib, "MINSHORT", INT2FIX(G_MINSHORT));
     rb_define_const(mGLib, "MAXSHORT", INT2FIX(G_MAXSHORT));
     rb_define_const(mGLib, "MAXUSHORT", INT2FIX(G_MAXUSHORT));
@@ -314,6 +315,7 @@ union       GDoubleIEEE754;
     Init_glib_unicode();
     Init_glib_keyfile();
     Init_glib_bookmark_file();
+  Init_glib_string();

     /* This is called here once. */
     G_DEF_SETTERS(mGLib);
diff --git a/glib/src/rbglib_string.c b/glib/src/rbglib_string.c
new file mode 100644
index 0000000..374c369
--- /dev/null
+++ b/glib/src/rbglib_string.c
@@ -0,0 +1,329 @@
+/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
+/************************************************
+
+  rbglib_string.c -
+
+  $Author: $
+  $Date: $
+
+  Copyright (C) 2009 Lionel L.
+************************************************/
+
+#include "rbgprivate.h"
+
+/************************************************/
+
+#define _SELF(self) ((GString*)(RVAL2BOXED(self, G_TYPE_GSTRING)))
+
+static VALUE
+string_initialize(argc, argv, self)
+    int argc;
+    VALUE *argv;
+    VALUE self;
+{
+        VALUE arg1;
+
+    if (argc == 0) {
+        G_INITIALIZE(self, g_string_new(NULL));
+    } else {
+        rb_scan_args(argc, argv, "1", &arg1);
+
+        if (TYPE(arg1) != T_STRING)
+            rb_raise(rb_eArgError, "argument should be a String");
+
+        G_INITIALIZE(self, g_string_new(STR2CSTR(arg1)));
+    }
+
+    return Qnil;
+}
+
+
+static VALUE
+string_equal(self, value)
+    VALUE self;
+    VALUE value;
+{
+    return CBOOL2RVAL(g_string_equal(_SELF(self), _SELF(value)));
+}
+
+static VALUE
+string_assign(self, value)
+    VALUE self;
+    VALUE value;
+{
+    if (TYPE(value) != T_STRING)
+        rb_raise(rb_eArgError, "argument should be a String");
+
+    g_string_assign(_SELF(self), STR2CSTR(value));
+
+    return self;
+}
+
+static VALUE
+string_truncate(self, len)
+    VALUE self;
+    VALUE len;
+{
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argment should be a Fixnum");
+
+    g_string_truncate(_SELF(self), FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_get_size(self)
+    VALUE self;
+{
+    return INT2FIX(_SELF(self)->len);
+}
+
+static VALUE
+string_set_size(self, size)
+    VALUE self;
+    VALUE size;
+{
+    if (!FIXNUM_P(size))
+        rb_raise(rb_eArgError, "argment should be a Fixnum");
+
+    g_string_set_size(_SELF(self), FIX2INT(size));
+
+    return self;
+}
+
+static VALUE
+string_get_char(self, pos)
+    VALUE self;
+    VALUE pos;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argment should be a Fixnum");
+
+    if (FIX2INT(pos) >= _SELF(self)->len)
+        return Qnil;
+
+    return INT2FIX(_SELF(self)->str[FIX2INT(pos)]);
+}
+
+static VALUE
+string_set_char(self, pos, value)
+    VALUE self;
+    VALUE pos;
+    VALUE value;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argment 1 should be a Fixnum");
+
+    if (!FIXNUM_P(value) && (FIX2INT(value) >= 256))
+        rb_raise(rb_eArgError, "argment 2 should be a Fixnum < 256");
+
+    _SELF(self)->str[FIX2INT(pos)] = (gchar) FIX2INT(value);
+
+    return self;
+}
+
+static VALUE
+string_append(self, data)
+    VALUE self;
+    VALUE data;
+{
+    if (FIXNUM_P(data) && (FIX2INT(data) < 256))
+        g_string_append_c(_SELF(self), (gchar) FIX2INT(data));
+    else if (TYPE(data) == T_STRING)
+        g_string_append(_SELF(self), STR2CSTR(data));
+    else
+        rb_raise(rb_eArgError, "argument should be a Fixnum < 256 or
String");
+
+    return self;
+}
+
+static VALUE
+string_append_len(self, str, len)
+    VALUE self;
+    VALUE str;
+    VALUE len;
+{
+    if (TYPE(str) != T_STRING)
+        rb_raise(rb_eArgError, "argument 1 should be a String");
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argument 2 should be a Fixnum");
+
+    g_string_append_len(_SELF(self), STR2CSTR(str), FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_prepend(self, data)
+    VALUE self;
+    VALUE data;
+{
+    if (FIXNUM_P(data) && (FIX2INT(data) < 256))
+        g_string_prepend_c(_SELF(self), (gchar) FIX2INT(data));
+    else if (TYPE(data) == T_STRING)
+        g_string_prepend(_SELF(self), STR2CSTR(data));
+    else
+        rb_raise(rb_eArgError, "argument should be a Fixnum or
String");
+
+    return self;
+}
+
+static VALUE
+string_prepend_len(self, str, len)
+    VALUE self;
+    VALUE str;
+    VALUE len;
+{
+    if (TYPE(str) != T_STRING)
+        rb_raise(rb_eArgError, "argument 1 should be a String");
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argument 2 should be a Fixnum");
+
+    g_string_prepend_len(_SELF(self), STR2CSTR(str), FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_insert(self, pos, data)
+    VALUE self;
+    VALUE pos;
+    VALUE data;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argument 1 should be a Fixnum");
+
+    if (FIXNUM_P(data) && (FIX2INT(data) < 256))
+        g_string_insert_c(_SELF(self), FIX2INT(pos), (gchar)
FIX2INT(data));
+    else if (TYPE(data) == T_STRING)
+        g_string_insert(_SELF(self), FIX2INT(pos), STR2CSTR(data));
+    else
+        rb_raise(rb_eArgError, "argument 2 should be a Fixnum or
String");
+
+    return self;
+}
+
+static VALUE
+string_insert_len(self, pos, str, len)
+    VALUE self;
+    VALUE pos;
+    VALUE str;
+    VALUE len;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argument 1 should be a Fixnum");
+
+    if (TYPE(str) != T_STRING)
+        rb_raise(rb_eArgError, "argument 2 should be a String");
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argument 3 should be a Fixnum");
+
+    g_string_insert_len(_SELF(self), FIX2INT(pos), STR2CSTR(str),
FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_overwrite(self, pos, data)
+    VALUE self;
+    VALUE pos;
+    VALUE data;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argument 1 should be a Fixnum");
+
+    if (FIXNUM_P(data) && (FIX2INT(data) < 256))
+        _SELF(self)->str[FIX2INT(pos)] = (gchar) FIX2INT(data);
+    else if (TYPE(data) == T_STRING)
+        g_string_overwrite(_SELF(self), FIX2INT(pos), STR2CSTR(data));
+    else
+        rb_raise(rb_eArgError, "argument 2 should be a Fixnum or
String");
+
+    return self;
+}
+
+static VALUE
+string_overwrite_len(self, pos, str, len)
+    VALUE self;
+    VALUE pos;
+    VALUE str;
+    VALUE len;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argument 1 should be a Fixnum");
+
+    if (TYPE(str) != T_STRING)
+        rb_raise(rb_eArgError, "argument 2 should be a String");
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argument 3 should be a Fixnum");
+
+    g_string_overwrite_len(_SELF(self), FIX2INT(pos), STR2CSTR(str),
FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_erase(self, pos, len)
+    VALUE self;
+    VALUE pos;
+    VALUE len;
+{
+    if (!FIXNUM_P(pos))
+        rb_raise(rb_eArgError, "argument 1 should be a Fixnum");
+    if (!FIXNUM_P(len))
+        rb_raise(rb_eArgError, "argument 2 should be a String");
+
+    g_string_erase(_SELF(self), FIX2INT(pos), FIX2INT(len));
+
+    return self;
+}
+
+static VALUE
+string_ascii_down(self)
+    VALUE self;
+{
+    g_string_ascii_down(_SELF(self));
+
+    return self;
+}
+
+static VALUE
+string_ascii_up(self)
+    VALUE self;
+{
+    g_string_ascii_up(_SELF(self));
+
+    return self;
+}
+
+void
+Init_glib_string()
+{
+    VALUE str = G_DEF_CLASS(G_TYPE_GSTRING, "String", mGLib);
+
+    rb_define_method(str, "initialize", string_initialize, -1);
+    rb_define_method(str, "==", string_equal, 1);
+    rb_define_method(str, "assign", string_assign, -1);
+    rb_define_method(str, "truncate", string_truncate, -1);
+
+    rb_define_method(str, "size", string_get_size, 0);
+    rb_define_method(str, "size=", string_set_size, 1);
+
+    rb_define_method(str, "[]", string_get_char, 1);
+    rb_define_method(str, "[]=", string_set_char, 2);
+
+    rb_define_method(str, "append", string_append, 1);
+    rb_define_method(str, "append_len", string_append_len, 2);
+    rb_define_method(str, "insert", string_insert, 2);
+    rb_define_method(str, "insert_len", string_insert_len, 3);
+    rb_define_method(str, "prepend", string_prepend, 1);
+    rb_define_method(str, "prepend_len", string_prepend_len, 1);
+    rb_define_method(str, "overwrite", string_overwrite, 2);
+    rb_define_method(str, "overwrite_len", string_overwrite_len, 3);
+
+    rb_define_method(str, "erase", string_erase, 2);
+
+    rb_define_method(str, "ascii_down", string_ascii_down, 0);
+    rb_define_method(str, "ascii_up", string_ascii_up, 0);
+}
--
1.6.3.1


--
Lionel L. <removed_email_address@domain.invalid>
Kouhei S. (Guest)
on 2009-05-26 14:50
(Received via mailing list)
Hi,

2009/5/26 Lionel L. <removed_email_address@domain.invalid>:
> Hi ruby-gnome2,
>
> For my personnal needs with Ruby GStreamer, I needed to access the
> g_string_* stuff in GLib.
> Here is a first try to implement the g_string_* stuff in a ruby class.
> Please tell me how to improve/add/remove things if necessary, so it
> could be integrated as soon as possible.

Could you show your GStreamer case?
If it really needs GStreing, we will accept the patch.

P.S. You can use ANSI style function definition instead of K&R:
func (a, b, c)
VALUE a, b, c;
{
}
 |
\/
func (VALUE a, VALUE b, VALUE c)
{
}

Thanks,
--
kou
Lionel L. (Guest)
on 2009-05-26 16:09
(Received via mailing list)
Attachment: test_ts_pids.rb (0 Bytes)
Le mardi 26 mai 2009 à 19:47 +0900, Kouhei S. a écrit :
>
> func (VALUE a, VALUE b, VALUE c)
> {
> }
>
> Thanks,
> --
> kou
>

About the coding style, I just followed the same rules than the other
files.

Here is an example.
It displays the GstStructure values emitted by the mpegtsparse plugin
from GStreamer. One of them are MPEG/TS descriptors, found in PSI
tables. They might contain more than one '\0' character, so g_string_*
is required.

Regards,
Lionel L. (Guest)
on 2009-05-26 23:16
(Received via mailing list)
Le mardi 26 mai 2009 à 01:34 +0200, Lionel L. a écrit :
> Hi ruby-gnome2,
>

Added 2 new methods : each_byte and to_a.

Regards,

--

Added to_a and each_byte methods

Signed-off-by: Lionel L. <removed_email_address@domain.invalid>
---
 glib/src/rbglib_string.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/glib/src/rbglib_string.c b/glib/src/rbglib_string.c
index 374c369..f71097e 100644
--- a/glib/src/rbglib_string.c
+++ b/glib/src/rbglib_string.c
@@ -107,6 +107,23 @@ string_get_char(self, pos)
 }

 static VALUE
+string_each_byte(self)
+    VALUE self;
+{
+    gsize i;
+
+    if (!rb_block_given_p()) {
+        rb_raise(rb_eArgError, "called without a block");
+    }
+
+    for (i = 0 ; i < _SELF(self)->len ; i++) {
+        rb_yield(UINT2NUM(_SELF(self)->str[i]));
+    }
+
+    return self;
+}
+
+static VALUE
 string_set_char(self, pos, value)
     VALUE self;
     VALUE pos;
@@ -297,6 +314,21 @@ string_ascii_up(self)
     return self;
 }

+static VALUE
+string_to_a(self)
+    VALUE self;
+{
+    gsize i;
+    VALUE ary;
+
+    ary = rb_ary_new();
+    for (i = 0 ; i < _SELF(self)->len ; i++) {
+        rb_ary_push(ary, UINT2NUM(_SELF(self)->str[i]));
+    }
+
+    return ary;
+}
+
 void
 Init_glib_string()
 {
@@ -313,6 +345,8 @@ Init_glib_string()
     rb_define_method(str, "[]", string_get_char, 1);
     rb_define_method(str, "[]=", string_set_char, 2);

+    rb_define_method(str, "each_byte", string_each_byte, 0);
+
     rb_define_method(str, "append", string_append, 1);
     rb_define_method(str, "append_len", string_append_len, 2);
     rb_define_method(str, "insert", string_insert, 2);
@@ -326,4 +360,6 @@ Init_glib_string()

     rb_define_method(str, "ascii_down", string_ascii_down, 0);
     rb_define_method(str, "ascii_up", string_ascii_up, 0);
+
+    rb_define_method(str, "to_a", string_to_a, 0);
 }
--
1.6.3.1

--
Lionel L. <removed_email_address@domain.invalid>
Kouhei S. (Guest)
on 2009-05-27 15:42
(Received via mailing list)
Hi,

2009/5/26 Lionel L. <removed_email_address@domain.invalid>:

> About the coding style, I just followed the same rules than the other
> files.

Yes. Many of the current source codes are written with K&R style.
But it's a historical reason. We are moving to ANSI style from K&R style
because Ruby itself were moved to ANSI style.

We want to use ANSI style for newly written codes.


> Here is an example.
> It displays the GstStructure values emitted by the mpegtsparse plugin
> from GStreamer. One of them are MPEG/TS descriptors, found in PSI
> tables. They might contain more than one '\0' character, so g_string_*
> is required.

Could you show us an example code?
I can't confirm the case because I don't have an environment for that...

Ruby's string can also contain more than '\0' character.
Is Ruby's string bad solution in the case?


Thanks,
--
kou
Lionel L. (Guest)
on 2009-05-27 16:54
(Received via mailing list)
Le mercredi 27 mai 2009 à 20:40 +0900, Kouhei S. a écrit :
> Hi,

Hi,

> We want to use ANSI style for newly written codes.
Ok, I will rewrite it using ANSI style.

>
>
> > Here is an example.
> > It displays the GstStructure values emitted by the mpegtsparse plugin
> > from GStreamer. One of them are MPEG/TS descriptors, found in PSI
> > tables. They might contain more than one '\0' character, so g_string_*
> > is required.
>
> Could you show us an example code?
> I can't confirm the case because I don't have an environment for that...

I already did that in my previous mail, can't you see the attachment ?
If not, you can get it at http://potipota.net/~djdeath/test_ts_pids.rb

If you're running a debian/ubuntu system, you need the following
packages :
      * gstreamer0.10-plugins-bad
      * ruby-gnome2

Then just run the test_ts_pids.rb script with the first argument beeing
a MPEG/TS file. You can download one from
http://potipota.net/~djdeath/NRJ_12_HD.ts


>
> Ruby's string can also contain more than '\0' character.
> Is Ruby's string bad solution in the case?

The problem is that GString is a boxed type.
For boxed types, ruby-gnome does the following conversion :
  Ruby String <-> GBoxed (gchar *)

So ruby cannot automaticly knows which conversion must be done :
  Ruby String <-> GBoxed (gchar *)
    or
  Ruby String <-> GBoxed (GLib String)

So introducing a new Ruby class to handle the GLib String component
seems to be the better solution to me (just like it has been done for
GKeyFile or GTimer).

--
Lionel L. <removed_email_address@domain.invalid>
Kouhei S. (Guest)
on 2009-05-27 17:20
(Received via mailing list)
Hi,

2009/5/27 Lionel L. <removed_email_address@domain.invalid>:

>> We want to use ANSI style for newly written codes.
>
> Ok, I will rewrite it using ANSI style.

Thanks!

> I already did that in my previous mail, can't you see the attachment ?

Oops...
Sorry... I missed it...

OK. I understood.


Do you have SF.net account?
I'll add you to the Ruby-GNOME2 developers, please commit your patch
by yourself. (It's more better that your patch also includes unit test.
:-)


Thanks,
--
kou
Lionel L. (Guest)
on 2009-05-28 09:38
(Received via mailing list)
Le mercredi 27 mai 2009 à 22:19 +0900, Kouhei S. a écrit :
> > I already did that in my previous mail, can't you see the attachment ?
>
Ok, I just created an account, login : llandwerlin


--
Lionel L. <removed_email_address@domain.invalid>
Kouhei S. (Guest)
on 2009-05-28 18:09
(Received via mailing list)
Hi,

2009/5/28 Lionel L. <removed_email_address@domain.invalid>:

>> Do you have SF.net account?
>> I'll add you to the Ruby-GNOME2 developers, please commit your patch
>> by yourself. (It's more better that your patch also includes unit test. :-)
>>
>
> Ok, I just created an account, login : llandwerlin

I've add you to the Ruby-GNOME2 developers. Welcome!

BTW, do you know rbgobj_register_g2r_func()?
Your case may be solved by the function without providing GString
bindings.

It's better that we use Ruby's String rather than GString bindings
because
users doesn't need to lean about new class and Ruby's string is more
powerful
rather than GString.
If you're interested in Rubyish API, please consider about the function
before
you commit your patch. :-)


Thanks,
--
kou
This topic is locked and can not be replied to.