00001
00002 #ifndef _FBUFFER_H_
00003 #define _FBUFFER_H_
00004
00005 #include "ruby.h"
00006
00007 #ifndef RHASH_SIZE
00008 #define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
00009 #endif
00010
00011 #ifndef RFLOAT_VALUE
00012 #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
00013 #endif
00014
00015 #ifndef RARRAY_PTR
00016 #define RARRAY_PTR(ARRAY) RARRAY(ARRAY)->ptr
00017 #endif
00018 #ifndef RARRAY_LEN
00019 #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
00020 #endif
00021 #ifndef RSTRING_PTR
00022 #define RSTRING_PTR(string) RSTRING(string)->ptr
00023 #endif
00024 #ifndef RSTRING_LEN
00025 #define RSTRING_LEN(string) RSTRING(string)->len
00026 #endif
00027
00028 #ifdef HAVE_RUBY_ENCODING_H
00029 #include "ruby/encoding.h"
00030 #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
00031 #else
00032 #define FORCE_UTF8(obj)
00033 #endif
00034
00035
00036 #ifndef RB_GC_GUARD
00037 #define RB_GC_GUARD(object)
00038 #endif
00039
00040 typedef struct FBufferStruct {
00041 unsigned long initial_length;
00042 char *ptr;
00043 unsigned long len;
00044 unsigned long capa;
00045 } FBuffer;
00046
00047 #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
00048
00049 #define FBUFFER_PTR(fb) (fb->ptr)
00050 #define FBUFFER_LEN(fb) (fb->len)
00051 #define FBUFFER_CAPA(fb) (fb->capa)
00052 #define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
00053
00054 static FBuffer *fbuffer_alloc(unsigned long initial_length);
00055 static void fbuffer_free(FBuffer *fb);
00056 static void fbuffer_clear(FBuffer *fb);
00057 static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
00058 #ifdef JSON_GENERATOR
00059 static void fbuffer_append_long(FBuffer *fb, long number);
00060 #endif
00061 static void fbuffer_append_char(FBuffer *fb, char newchr);
00062 #ifdef JSON_GENERATOR
00063 static FBuffer *fbuffer_dup(FBuffer *fb);
00064 static VALUE fbuffer_to_s(FBuffer *fb);
00065 #endif
00066
00067 static FBuffer *fbuffer_alloc(unsigned long initial_length)
00068 {
00069 FBuffer *fb;
00070 if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
00071 fb = ALLOC(FBuffer);
00072 memset((void *) fb, 0, sizeof(FBuffer));
00073 fb->initial_length = initial_length;
00074 return fb;
00075 }
00076
00077 static void fbuffer_free(FBuffer *fb)
00078 {
00079 if (fb->ptr) ruby_xfree(fb->ptr);
00080 ruby_xfree(fb);
00081 }
00082
00083 static void fbuffer_clear(FBuffer *fb)
00084 {
00085 fb->len = 0;
00086 }
00087
00088 static void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
00089 {
00090 unsigned long required;
00091
00092 if (!fb->ptr) {
00093 fb->ptr = ALLOC_N(char, fb->initial_length);
00094 fb->capa = fb->initial_length;
00095 }
00096
00097 for (required = fb->capa; requested > required - fb->len; required <<= 1);
00098
00099 if (required > fb->capa) {
00100 REALLOC_N(fb->ptr, char, required);
00101 fb->capa = required;
00102 }
00103 }
00104
00105 static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
00106 {
00107 if (len > 0) {
00108 fbuffer_inc_capa(fb, len);
00109 MEMCPY(fb->ptr + fb->len, newstr, char, len);
00110 fb->len += len;
00111 }
00112 }
00113
00114 #ifdef JSON_GENERATOR
00115 static void fbuffer_append_str(FBuffer *fb, VALUE str)
00116 {
00117 const char *newstr = StringValuePtr(str);
00118 unsigned long len = RSTRING_LEN(str);
00119
00120 RB_GC_GUARD(str);
00121
00122 fbuffer_append(fb, newstr, len);
00123 }
00124 #endif
00125
00126 static void fbuffer_append_char(FBuffer *fb, char newchr)
00127 {
00128 fbuffer_inc_capa(fb, 1);
00129 *(fb->ptr + fb->len) = newchr;
00130 fb->len++;
00131 }
00132
00133 #ifdef JSON_GENERATOR
00134 static void freverse(char *start, char *end)
00135 {
00136 char c;
00137
00138 while (end > start) {
00139 c = *end, *end-- = *start, *start++ = c;
00140 }
00141 }
00142
00143 static long fltoa(long number, char *buf)
00144 {
00145 static char digits[] = "0123456789";
00146 long sign = number;
00147 char* tmp = buf;
00148
00149 if (sign < 0) number = -number;
00150 do *tmp++ = digits[number % 10]; while (number /= 10);
00151 if (sign < 0) *tmp++ = '-';
00152 freverse(buf, tmp - 1);
00153 return tmp - buf;
00154 }
00155
00156 static void fbuffer_append_long(FBuffer *fb, long number)
00157 {
00158 char buf[20];
00159 unsigned long len = fltoa(number, buf);
00160 fbuffer_append(fb, buf, len);
00161 }
00162
00163 static FBuffer *fbuffer_dup(FBuffer *fb)
00164 {
00165 unsigned long len = fb->len;
00166 FBuffer *result;
00167
00168 result = fbuffer_alloc(len);
00169 fbuffer_append(result, FBUFFER_PAIR(fb));
00170 return result;
00171 }
00172
00173 static VALUE fbuffer_to_s(FBuffer *fb)
00174 {
00175 VALUE result = rb_str_new(FBUFFER_PAIR(fb));
00176 fbuffer_free(fb);
00177 FORCE_UTF8(result);
00178 return result;
00179 }
00180 #endif
00181 #endif
00182