Saluton!

* Michael Neumann; 2003-06-13, 23:05 UTC:
> Why not make Storage a class, so you can have more than one? Your
> current implementation does not allow this.

Done.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

# EXAMPLE of using 'Storage':

require 'Storage'  # Require library
s = Storage.new(3) # s is to hold 3 chars
s.append('foo')    # append 'foo' to s
s.append('bar')    # append 'bar' to s (s grows to hold text)
s.append('baz')    # append 'baz' to s (s grows to hold text)
puts s.to_s        # prints 'foobarbaz'
s.resize(6)        # shrink s to hold 6 chars
puts s.to_s        # prints 'foobar'
s.flush            # flushes content of s
puts s.to_s.length # 0
puts s.capacity    # 6

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

#include <ruby.h>
#include <string.h>

VALUE cStorage;

typedef struct {
  char *start, *end;
  int  capacity;
} mem;


static VALUE freemem(mem *m) {
  free(m->start);
  free(m);
  return Qnil;
}

VALUE new(VALUE class, VALUE size) {
  int n;
  mem *m = ALLOC(mem);
  VALUE data;
  Check_Type(size, T_FIXNUM);
  *(m->end = m->start = ALLOC_N(char, (n = NUM2ULONG(size)) + 1)) = '\0';
  m->capacity = n;
  data = Data_Wrap_Struct(class, NULL, freemem, m);
  rb_obj_call_init(data, 0, NULL);
  return data;
}

static VALUE append(VALUE self, VALUE text) {
  mem  *m;
  char *s, *t;
  int  old, plus, need;

  Data_Get_Struct(self, mem, m);

  if ((need = (plus = strlen(s = STR2CSTR(text))) + (old = m->end - (t = m->start))) >= m->capacity) {
    REALLOC_N(m->start, char, (m->capacity = need) + 1);
    if (t != m->start) m->end = m->start + old;
  }
  strcpy(m->end, s);
  m->end += plus;
  return Qnil;
}

static VALUE resize(VALUE self, VALUE size) {
  mem *m;
  int n, len;
  char *s;
  Data_Get_Struct(self, mem, m);
  Check_Type(size, T_FIXNUM);
  len = m->end - (s = m->start);
  REALLOC_N(m->start, char, (m->capacity = n = NUM2ULONG(size)) + 1);
  if (s != m->start) m->end = m->start + ((n < len) ? n : len);
  *(m->start + n) = '\0';
  return Qnil;
}

static VALUE flush(VALUE self) {
  mem *m;
  Data_Get_Struct(self, mem, m);
  *(m->end = m->start) = '\0';
  return Qnil;
}

static VALUE to_s(VALUE self) {
  mem *m;
  Data_Get_Struct(self, mem, m);
  return rb_str_new2(m->start);
}

static VALUE capacity(VALUE self) {
  mem *m;
  Data_Get_Struct(self, mem, m);
  return INT2NUM(m->capacity);
}

void Init_Storage() {
  cStorage = rb_define_class("Storage", rb_cObject);
  rb_define_singleton_method(cStorage, "new", new, 1);
  rb_define_method(cStorage, "append",   append,   1);
  rb_define_method(cStorage, "to_s",     to_s,     0);
  rb_define_method(cStorage, "resize",   resize,   1);
  rb_define_method(cStorage, "flush",    flush,    0);
  rb_define_method(cStorage, "capacity", capacity, 0);
}
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Gis,

Josef 'Jupp' Schugt