/**********************************************************************

  string.c -

**********************************************************************/

#include "ruby.h"
#include "re.h"

#define BEG(no) regs->beg[no]
#define END(no) regs->end[no]

#include <math.h>
#include <ctype.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

VALUE rb_cString;

#define STR_NO_ORIG FL_USER2
#define STR_ASSOC   FL_USER3

VALUE rb_fs;

@@@@@begin rb_str_new
VALUE
rb_str_new(ptr, len)
    const char *ptr;
    long len;
@@@@@body
{
    NEWOBJ(str, struct RString);
    OBJSETUP(str, rb_cString, T_STRING);

    str->ptr = 0;
    str->len = len;
    str->orig = 0;
    str->ptr = ALLOC_N(char,len+1);
    if (ptr) {
	memcpy(str->ptr, ptr, len);
    }
    str->ptr[len] = '\0';
    return (VALUE)str;
}
@@@@@end

@@@@@begin rb_str_new2
VALUE
rb_str_new2(ptr)
    const char *ptr;
@@@@@body
{
    return rb_str_new(ptr, strlen(ptr));
}
@@@@@end

@@@@@begin rb_tainted_str_new
VALUE
rb_tainted_str_new(ptr, len)
    const char *ptr;
    long len;
@@@@@body
{
    VALUE str = rb_str_new(ptr, len);

    OBJ_TAINT(str);
    return str;
}
@@@@@end

@@@@@begin rb_str_become
static void
rb_str_become(str, str2)
    VALUE str, str2;
@@@@@body
{
    if (str == str2) return;
    if (NIL_P(str2)) {
	RSTRING(str)->ptr = 0;
	RSTRING(str)->len = 0;
	RSTRING(str)->orig = 0;
	return;
    }
    if ((!RSTRING(str)->orig||FL_TEST(str,STR_NO_ORIG))&&RSTRING(str)->ptr)
	free(RSTRING(str)->ptr);
    RSTRING(str)->ptr = RSTRING(str2)->ptr;
    RSTRING(str)->len = RSTRING(str2)->len;
    RSTRING(str)->orig = RSTRING(str2)->orig;
    RSTRING(str2)->ptr = 0;	/* abandon str2 */
    RSTRING(str2)->len = 0;
    if (OBJ_TAINTED(str2)) OBJ_TAINT(str);
}
@@@@@end

@@@@@begin rb_str_associate
void
rb_str_associate(str, add)
    VALUE str, add;
@@@@@body
{
    if (FL_TEST(str, STR_NO_ORIG|STR_ASSOC) != (STR_NO_ORIG|STR_ASSOC)) {
	if (FL_TEST(str, STR_NO_ORIG)) {
	    /* str_buf */
	    if (FIX2LONG(RSTRING(str)->orig) != RSTRING(str)->len) {
		REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + 1);
	    }
	}
	else if (RSTRING(str)->orig) {
	    rb_str_modify(str);
	}
	RSTRING(str)->orig = add;
	FL_SET(str, STR_NO_ORIG|STR_ASSOC);
    }
    else {
	/* already associated */
	rb_ary_concat(RSTRING(str)->orig, add);
    }
}
@@@@@end

static ID id_to_s;

@@@@@begin rb_obj_as_string
VALUE
rb_obj_as_string(obj)
    VALUE obj;
@@@@@body
{
    VALUE str;

    if (TYPE(obj) == T_STRING) {
	return obj;
    }
    str = rb_funcall(obj, id_to_s, 0);
    if (TYPE(str) != T_STRING)
	return rb_any_to_s(obj);
    if (OBJ_TAINTED(obj)) OBJ_TAINT(str);
    return str;
}
@@@@@end

@@@@@begin err_print
static void err_append _((const char*));
static void
err_print(fmt, args)
    const char *fmt;
    va_list args;
@@@@@body
{
    char buf[BUFSIZ];

    err_snprintf(buf, BUFSIZ, fmt, args);
    err_append(buf);
}
@@@@@end


@@@@@begin rb_rescue2
VALUE
#ifdef HAVE_STDARG_PROTOTYPES
rb_rescue2(VALUE (*b_proc)(), VALUE data1, VALUE (*r_proc)(), VALUE data2, ...)
#else
rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
    VALUE (*b_proc)(), (*r_proc)();
    VALUE data1, data2;
    va_dcl
#endif
@@@@@body
{
    int state;
    volatile VALUE result;
    volatile VALUE e_info = ruby_errinfo;
    va_list args;

    PUSH_TAG(PROT_NONE);
    POP_TAG();
    if (state) JUMP_TAG(state);

    return result;
}
@@@@@end

@@@@@begin scan_oct
unsigned long
scan_oct(start, len, retlen)
const char *start;
int len;
int *retlen;
@@@@@body
{
    register const char *s = start;
    register unsigned long retval = 0;

    while (len-- && *s >= '0' && *s <= '7') {
	retval <<= 3;
	retval |= *s++ - '0';
    }
    *retlen = s - start;
    return retval;
}
@@@@@end

@@@@@begin mmprepare
static void mmprepare(base, size) void *base; int size;
@@@@@body
{
#ifdef DEBUG
 if (sizeof(int) != 4) die("sizeof(int) != 4");
 if (size <= 0) die("mmsize <= 0");
#endif

 if (((long)base & (4-1)) == 0 && ((long)base & (4-1)) == 0)
   if (size >= 16) mmkind = 1;
   else            mmkind = 0;
 else              mmkind = -1;
 
 mmsize = size;
 high = (size & (-16));
 low  = (size & 0x0c);
}
@@@@@end

@@@@@begin ruby_qsort
void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)();
@@@@@body
{
  register char *l, *r, *m;
  register int  t, eq_l, eq_r;
  char *L = base;
  char *R = (char*)base + size*(nel-1);
  int  chklim = 63;
  stack_node stack[32], *top = stack;

  if (nel <= 1) return;
}
@@@@@end
