~ubuntu-branches/ubuntu/intrepid/ruby1.9/intrepid-updates

« back to all changes in this revision

Viewing changes to ext/json/ext/generator/generator.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-09-04 16:01:17 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070904160117-i15zckg2nhxe9fyw
Tags: 1.9.0+20070830-2ubuntu1
* Sync from Debian; remaining changes:
  - Add -g to CFLAGS.
* Fixes build failure on ia64.
* Fixes build failure with gcc-4.2 on lpia.
* Robustify check for target_os, fixing build failure on lpia.
* Set Ubuntu maintainer address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* vim: set cin et sw=4 ts=4: */
2
2
 
 
3
#include "ruby/ruby.h"
 
4
#include "ruby/st.h"
 
5
#include "unicode.h"
3
6
#include <string.h>
4
 
#include "ruby.h"
5
 
#include "st.h"
6
 
#include "unicode.h"
 
7
#include <math.h>
 
8
 
 
9
#define check_max_nesting(state, depth) do {                                   \
 
10
    long current_nesting = 1 + depth;                                          \
 
11
    if (state->max_nesting != 0 && current_nesting > state->max_nesting)       \
 
12
        rb_raise(eNestingError, "nesting of %ld is too deep", current_nesting); \
 
13
} while (0);
7
14
 
8
15
static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
9
16
             mHash, mArray, mInteger, mFloat, mString, mString_Extend,
10
17
             mTrueClass, mFalseClass, mNilClass, eGeneratorError,
11
 
             eCircularDatastructure;
 
18
             eCircularDatastructure, eNestingError;
12
19
 
13
20
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
14
 
          i_object_nl, i_array_nl, i_check_circular, i_pack, i_unpack,
15
 
          i_create_id, i_extend;
 
21
          i_object_nl, i_array_nl, i_check_circular, i_max_nesting,
 
22
          i_allow_nan, i_pack, i_unpack, i_create_id, i_extend;
16
23
 
17
24
typedef struct JSON_Generator_StateStruct {
18
25
    VALUE indent;
24
31
    VALUE seen;
25
32
    VALUE memo;
26
33
    VALUE depth;
 
34
    long max_nesting;
27
35
    int flag;
 
36
    int allow_nan;
28
37
} JSON_Generator_State;
29
38
 
30
39
#define GET_STATE(self)                       \
77
86
}
78
87
 
79
88
inline static VALUE mHash_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth) {
80
 
    long depth, len = RHASH(self)->tbl->num_entries;
 
89
    long depth, len = RHASH_SIZE(self);
81
90
    VALUE result;
82
91
    GET_STATE(Vstate);
83
92
 
131
140
    rb_scan_args(argc, argv, "02", &Vstate, &Vdepth);
132
141
    depth = NIL_P(Vdepth) ? 0 : FIX2LONG(Vdepth);
133
142
    if (NIL_P(Vstate)) {
134
 
        long len = RHASH(self)->tbl->num_entries;
 
143
        long len = RHASH_SIZE(self);
135
144
        result = rb_str_buf_new(len);
136
145
        rb_str_buf_cat2(result, "{");
137
146
        rb_hash_foreach(self, hash_to_json_i, result);
138
147
        rb_str_buf_cat2(result, "}");
139
148
    } else {
140
149
        GET_STATE(Vstate);
 
150
        check_max_nesting(state, depth);
141
151
        if (state->check_circular) {
142
152
            VALUE self_id = rb_obj_id(self);
143
153
            if (RTEST(rb_hash_aref(state->seen, self_id))) {
162
172
    VALUE delim = rb_str_new2(",");
163
173
    GET_STATE(Vstate);
164
174
 
 
175
    check_max_nesting(state, depth);
165
176
    if (state->check_circular) {
166
177
        VALUE self_id = rb_obj_id(self);
167
178
        rb_hash_aset(state->seen, self_id, Qtrue);
170
181
        shift = rb_str_times(state->indent, LONG2FIX(depth + 1));
171
182
 
172
183
        rb_str_buf_cat2(result, "[");
 
184
        OBJ_INFECT(result, self);
173
185
        rb_str_buf_append(result, state->array_nl);
174
186
        for (i = 0;  i < len; i++) {
175
187
            VALUE element = RARRAY_PTR(self)[i];
190
202
        rb_hash_delete(state->seen, self_id);
191
203
    } else {
192
204
        result = rb_str_buf_new(len);
 
205
        OBJ_INFECT(result, self);
193
206
        if (RSTRING_LEN(state->array_nl)) rb_str_append(delim, state->array_nl);
194
207
        shift = rb_str_times(state->indent, LONG2FIX(depth + 1));
195
208
 
228
241
        long i, len = RARRAY_LEN(self);
229
242
        result = rb_str_buf_new(2 + 2 * len);
230
243
        rb_str_buf_cat2(result, "[");
 
244
        OBJ_INFECT(result, self);
231
245
        for (i = 0;  i < len; i++) {
232
246
            VALUE element = RARRAY_PTR(self)[i];
233
247
            OBJ_INFECT(result, element);
259
273
 */
260
274
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
261
275
{
262
 
    return rb_funcall(self, i_to_s, 0);
 
276
    JSON_Generator_State *state = NULL;
 
277
    VALUE Vstate, rest, tmp;
 
278
    double value = RFLOAT(self)->value;
 
279
    rb_scan_args(argc, argv, "01*", &Vstate, &rest);
 
280
    if (!NIL_P(Vstate)) Data_Get_Struct(Vstate, JSON_Generator_State, state);
 
281
    if (isinf(value)) {
 
282
        if (!state || state->allow_nan) {
 
283
            return rb_funcall(self, i_to_s, 0);
 
284
        } else {
 
285
            tmp = rb_funcall(self, i_to_s, 0);
 
286
            rb_raise(eGeneratorError, "%s not allowed in JSON", StringValueCStr(tmp));
 
287
        }
 
288
    } else if (isnan(value)) {
 
289
        if (!state || state->allow_nan) {
 
290
            return rb_funcall(self, i_to_s, 0);
 
291
        } else {
 
292
            tmp = rb_funcall(self, i_to_s, 0);
 
293
            rb_raise(eGeneratorError, "%s not allowed in JSON", StringValueCStr(tmp));
 
294
        }
 
295
    } else {
 
296
        return rb_funcall(self, i_to_s, 0);
 
297
    }
263
298
}
264
299
 
265
300
/*
404
439
}
405
440
 
406
441
/*
 
442
 * call-seq: configure(opts)
 
443
 *
 
444
 * Configure this State instance with the Hash _opts_, and return
 
445
 * itself.
 
446
 */
 
447
static inline VALUE cState_configure(VALUE self, VALUE opts)
 
448
{
 
449
    VALUE tmp;
 
450
    GET_STATE(self);
 
451
    tmp = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
 
452
    if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
 
453
    if (NIL_P(tmp)) {
 
454
        rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
 
455
    }
 
456
    opts = tmp;
 
457
    tmp = rb_hash_aref(opts, ID2SYM(i_indent));
 
458
    if (RTEST(tmp)) {
 
459
        Check_Type(tmp, T_STRING);
 
460
        state->indent = tmp;
 
461
    }
 
462
    tmp = rb_hash_aref(opts, ID2SYM(i_space));
 
463
    if (RTEST(tmp)) {
 
464
        Check_Type(tmp, T_STRING);
 
465
        state->space = tmp;
 
466
    }
 
467
    tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
 
468
    if (RTEST(tmp)) {
 
469
        Check_Type(tmp, T_STRING);
 
470
        state->space_before = tmp;
 
471
    }
 
472
    tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
 
473
    if (RTEST(tmp)) {
 
474
        Check_Type(tmp, T_STRING);
 
475
        state->array_nl = tmp;
 
476
    }
 
477
    tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
 
478
    if (RTEST(tmp)) {
 
479
        Check_Type(tmp, T_STRING);
 
480
        state->object_nl = tmp;
 
481
    }
 
482
    tmp = ID2SYM(i_check_circular);
 
483
    if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
 
484
        tmp = rb_hash_aref(opts, ID2SYM(i_check_circular));
 
485
        state->check_circular = RTEST(tmp);
 
486
    } else {
 
487
        state->check_circular = 1;
 
488
    }
 
489
    tmp = ID2SYM(i_max_nesting);
 
490
    state->max_nesting = 19;
 
491
    if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
 
492
        VALUE max_nesting = rb_hash_aref(opts, tmp);
 
493
        if (RTEST(max_nesting)) {
 
494
            Check_Type(max_nesting, T_FIXNUM);
 
495
            state->max_nesting = FIX2LONG(max_nesting);
 
496
        } else {
 
497
            state->max_nesting = 0;
 
498
        }
 
499
    }
 
500
    tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan));
 
501
    state->allow_nan = RTEST(tmp);
 
502
    return self;
 
503
}
 
504
 
 
505
/*
 
506
 * call-seq: to_h
 
507
 *
 
508
 * Returns the configuration instance variables as a hash, that can be
 
509
 * passed to the configure method.
 
510
 */
 
511
static VALUE cState_to_h(VALUE self)
 
512
{
 
513
    VALUE result = rb_hash_new();
 
514
    GET_STATE(self);
 
515
    rb_hash_aset(result, ID2SYM(i_indent), state->indent);
 
516
    rb_hash_aset(result, ID2SYM(i_space), state->space);
 
517
    rb_hash_aset(result, ID2SYM(i_space_before), state->space_before);
 
518
    rb_hash_aset(result, ID2SYM(i_object_nl), state->object_nl);
 
519
    rb_hash_aset(result, ID2SYM(i_array_nl), state->array_nl);
 
520
    rb_hash_aset(result, ID2SYM(i_check_circular), state->check_circular ? Qtrue : Qfalse);
 
521
    rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
 
522
    rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
 
523
    return result;
 
524
}
 
525
 
 
526
 
 
527
/*
407
528
 * call-seq: new(opts = {})
408
529
 *
409
530
 * Instantiates a new State object, configured by _opts_.
417
538
 * * *array_nl*: a string that is put at the end of a JSON array (default: ''),
418
539
 * * *check_circular*: true if checking for circular data structures
419
540
 *   should be done, false (the default) otherwise.
 
541
 * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
 
542
 *   generated, otherwise an exception is thrown, if these values are
 
543
 *   encountered. This options defaults to false.
420
544
 */
421
545
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
422
546
{
424
548
    GET_STATE(self);
425
549
 
426
550
    rb_scan_args(argc, argv, "01", &opts);
 
551
    state->indent = rb_str_new2("");
 
552
    state->space = rb_str_new2("");
 
553
    state->space_before = rb_str_new2("");
 
554
    state->array_nl = rb_str_new2("");
 
555
    state->object_nl = rb_str_new2("");
427
556
    if (NIL_P(opts)) {
428
 
        state->indent = rb_str_new2("");
429
 
        state->space = rb_str_new2("");
430
 
        state->space_before = rb_str_new2("");
431
 
        state->array_nl = rb_str_new2("");
432
 
        state->object_nl = rb_str_new2("");
433
 
        state->check_circular = 0;
 
557
        state->check_circular = 1;
 
558
        state->allow_nan = 0;
 
559
        state->max_nesting = 19;
434
560
    } else {
435
 
        VALUE tmp;
436
 
        opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
437
 
        tmp = rb_hash_aref(opts, ID2SYM(i_indent));
438
 
        if (RTEST(tmp)) {
439
 
            Check_Type(tmp, T_STRING);
440
 
            state->indent = tmp;
441
 
        } else {
442
 
            state->indent = rb_str_new2("");
443
 
        }
444
 
        tmp = rb_hash_aref(opts, ID2SYM(i_space));
445
 
        if (RTEST(tmp)) {
446
 
            Check_Type(tmp, T_STRING);
447
 
            state->space = tmp;
448
 
        } else {
449
 
            state->space = rb_str_new2("");
450
 
        }
451
 
        tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
452
 
        if (RTEST(tmp)) {
453
 
            Check_Type(tmp, T_STRING);
454
 
            state->space_before = tmp;
455
 
        } else {
456
 
            state->space_before = rb_str_new2("");
457
 
        }
458
 
        tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
459
 
        if (RTEST(tmp)) {
460
 
            Check_Type(tmp, T_STRING);
461
 
            state->array_nl = tmp;
462
 
        } else {
463
 
            state->array_nl = rb_str_new2("");
464
 
        }
465
 
        tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
466
 
        if (RTEST(tmp)) {
467
 
            Check_Type(tmp, T_STRING);
468
 
            state->object_nl = tmp;
469
 
        } else {
470
 
            state->object_nl = rb_str_new2("");
471
 
        }
472
 
        tmp = rb_hash_aref(opts, ID2SYM(i_check_circular));
473
 
        state->check_circular = RTEST(tmp);
 
561
        cState_configure(self, opts);
474
562
    }
475
563
    state->seen = rb_hash_new();
476
564
    state->memo = Qnil;
616
704
}
617
705
 
618
706
/*
619
 
 * call-seq: check_circular?(object)
 
707
 * call-seq: check_circular?
620
708
 *
621
709
 * Returns true, if circular data structures should be checked,
622
710
 * otherwise returns false.
628
716
}
629
717
 
630
718
/*
 
719
 * call-seq: max_nesting
 
720
 *
 
721
 * This integer returns the maximum level of data structure nesting in
 
722
 * the generated JSON, max_nesting = 0 if no maximum is checked.
 
723
 */
 
724
static VALUE cState_max_nesting(VALUE self)
 
725
{
 
726
    GET_STATE(self);
 
727
    return LONG2FIX(state->max_nesting);
 
728
}
 
729
 
 
730
/*
 
731
 * call-seq: max_nesting=(depth)
 
732
 *
 
733
 * This sets the maximum level of data structure nesting in the generated JSON
 
734
 * to the integer depth, max_nesting = 0 if no maximum should be checked.
 
735
 */
 
736
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
 
737
{
 
738
    GET_STATE(self);
 
739
    Check_Type(depth, T_FIXNUM);
 
740
    state->max_nesting = FIX2LONG(depth);
 
741
    return Qnil;
 
742
}
 
743
 
 
744
/*
 
745
 * call-seq: allow_nan?
 
746
 *
 
747
 * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
 
748
 * returns false.
 
749
 */
 
750
static VALUE cState_allow_nan_p(VALUE self)
 
751
{
 
752
    GET_STATE(self);
 
753
    return state->allow_nan ? Qtrue : Qfalse;
 
754
}
 
755
 
 
756
/*
631
757
 * call-seq: seen?(object)
632
758
 *
633
759
 * Returns _true_, if _object_ was already seen during this generating run. 
668
794
    mGenerator = rb_define_module_under(mExt, "Generator");
669
795
    eGeneratorError = rb_path2class("JSON::GeneratorError");
670
796
    eCircularDatastructure = rb_path2class("JSON::CircularDatastructure");
 
797
    eNestingError = rb_path2class("JSON::NestingError");
671
798
    cState = rb_define_class_under(mGenerator, "State", rb_cObject);
672
799
    rb_define_alloc_func(cState, cState_s_allocate);
673
800
    rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
684
811
    rb_define_method(cState, "array_nl", cState_array_nl, 0);
685
812
    rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
686
813
    rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
 
814
    rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
 
815
    rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
 
816
    rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
687
817
    rb_define_method(cState, "seen?", cState_seen_p, 1);
688
818
    rb_define_method(cState, "remember", cState_remember, 1);
689
819
    rb_define_method(cState, "forget", cState_forget, 1);
 
820
    rb_define_method(cState, "configure", cState_configure, 1);
 
821
    rb_define_method(cState, "to_h", cState_to_h, 0);
 
822
 
690
823
    mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
691
824
    mObject = rb_define_module_under(mGeneratorMethods, "Object");
692
825
    rb_define_method(mObject, "to_json", mObject_to_json, -1);
721
854
    i_object_nl = rb_intern("object_nl");
722
855
    i_array_nl = rb_intern("array_nl");
723
856
    i_check_circular = rb_intern("check_circular");
 
857
    i_max_nesting = rb_intern("max_nesting");
 
858
    i_allow_nan = rb_intern("allow_nan");
724
859
    i_pack = rb_intern("pack");
725
860
    i_unpack = rb_intern("unpack");
726
861
    i_create_id = rb_intern("create_id");