00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/util.h"
00017 #include "ruby/encoding.h"
00018 #include "internal.h"
00019 #include <errno.h>
00020 #include "probes.h"
00021
00022 #ifdef __APPLE__
00023 # ifdef HAVE_CRT_EXTERNS_H
00024 # include <crt_externs.h>
00025 # else
00026 # include "missing/crt_externs.h"
00027 # endif
00028 #endif
00029
00030 static VALUE rb_hash_s_try_convert(VALUE, VALUE);
00031
00032 #define HASH_DELETED FL_USER1
00033 #define HASH_PROC_DEFAULT FL_USER2
00034
00035 VALUE
00036 rb_hash_freeze(VALUE hash)
00037 {
00038 return rb_obj_freeze(hash);
00039 }
00040
00041 VALUE rb_cHash;
00042
00043 static VALUE envtbl;
00044 static ID id_hash, id_yield, id_default;
00045
00046 static int
00047 rb_any_cmp(VALUE a, VALUE b)
00048 {
00049 if (a == b) return 0;
00050 if (FIXNUM_P(a) && FIXNUM_P(b)) {
00051 return a != b;
00052 }
00053 if (RB_TYPE_P(a, T_STRING) && RBASIC(a)->klass == rb_cString &&
00054 RB_TYPE_P(b, T_STRING) && RBASIC(b)->klass == rb_cString) {
00055 return rb_str_hash_cmp(a, b);
00056 }
00057 if (a == Qundef || b == Qundef) return -1;
00058 if (SYMBOL_P(a) && SYMBOL_P(b)) {
00059 return a != b;
00060 }
00061
00062 return !rb_eql(a, b);
00063 }
00064
00065 VALUE
00066 rb_hash(VALUE obj)
00067 {
00068 VALUE hval = rb_funcall(obj, id_hash, 0);
00069 retry:
00070 switch (TYPE(hval)) {
00071 case T_FIXNUM:
00072 return hval;
00073
00074 case T_BIGNUM:
00075 return LONG2FIX(((long*)(RBIGNUM_DIGITS(hval)))[0]);
00076
00077 default:
00078 hval = rb_to_int(hval);
00079 goto retry;
00080 }
00081 }
00082
00083 static st_index_t
00084 rb_any_hash(VALUE a)
00085 {
00086 VALUE hval;
00087 st_index_t hnum;
00088
00089 if (SPECIAL_CONST_P(a)) {
00090 if (a == Qundef) return 0;
00091 hnum = rb_hash_end(rb_hash_start((st_index_t)a));
00092 }
00093 else if (BUILTIN_TYPE(a) == T_STRING) {
00094 hnum = rb_str_hash(a);
00095 }
00096 else {
00097 hval = rb_hash(a);
00098 hnum = FIX2LONG(hval);
00099 }
00100 hnum <<= 1;
00101 return (st_index_t)RSHIFT(hnum, 1);
00102 }
00103
00104 static const struct st_hash_type objhash = {
00105 rb_any_cmp,
00106 rb_any_hash,
00107 };
00108
00109 extern const struct st_hash_type st_hashtype_num;
00110 #define identhash st_hashtype_num
00111
00112 typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
00113
00114 struct foreach_safe_arg {
00115 st_table *tbl;
00116 st_foreach_func *func;
00117 st_data_t arg;
00118 };
00119
00120 static int
00121 foreach_safe_i(st_data_t key, st_data_t value, struct foreach_safe_arg *arg)
00122 {
00123 int status;
00124
00125 status = (*arg->func)(key, value, arg->arg);
00126 if (status == ST_CONTINUE) {
00127 return ST_CHECK;
00128 }
00129 return status;
00130 }
00131
00132 void
00133 st_foreach_safe(st_table *table, int (*func)(ANYARGS), st_data_t a)
00134 {
00135 struct foreach_safe_arg arg;
00136
00137 arg.tbl = table;
00138 arg.func = (st_foreach_func *)func;
00139 arg.arg = a;
00140 if (st_foreach_check(table, foreach_safe_i, (st_data_t)&arg, 0)) {
00141 rb_raise(rb_eRuntimeError, "hash modified during iteration");
00142 }
00143 }
00144
00145 typedef int rb_foreach_func(VALUE, VALUE, VALUE);
00146
00147 struct hash_foreach_arg {
00148 VALUE hash;
00149 rb_foreach_func *func;
00150 VALUE arg;
00151 };
00152
00153 static int
00154 hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp)
00155 {
00156 struct hash_foreach_arg *arg = (struct hash_foreach_arg *)argp;
00157 int status;
00158 st_table *tbl;
00159
00160 tbl = RHASH(arg->hash)->ntbl;
00161 status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
00162 if (RHASH(arg->hash)->ntbl != tbl) {
00163 rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
00164 }
00165 switch (status) {
00166 case ST_DELETE:
00167 FL_SET(arg->hash, HASH_DELETED);
00168 return ST_DELETE;
00169 case ST_CONTINUE:
00170 break;
00171 case ST_STOP:
00172 return ST_STOP;
00173 }
00174 return ST_CHECK;
00175 }
00176
00177 static VALUE
00178 hash_foreach_ensure(VALUE hash)
00179 {
00180 if (--RHASH_ITER_LEV(hash) == 0) {
00181 if (FL_TEST(hash, HASH_DELETED)) {
00182 st_cleanup_safe(RHASH(hash)->ntbl, (st_data_t)Qundef);
00183 FL_UNSET(hash, HASH_DELETED);
00184 }
00185 }
00186 return 0;
00187 }
00188
00189 static VALUE
00190 hash_foreach_call(VALUE arg)
00191 {
00192 VALUE hash = ((struct hash_foreach_arg *)arg)->hash;
00193 if (st_foreach_check(RHASH(hash)->ntbl, hash_foreach_iter, (st_data_t)arg, (st_data_t)Qundef)) {
00194 rb_raise(rb_eRuntimeError, "hash modified during iteration");
00195 }
00196 return Qnil;
00197 }
00198
00199 void
00200 rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
00201 {
00202 struct hash_foreach_arg arg;
00203
00204 if (!RHASH(hash)->ntbl)
00205 return;
00206 RHASH_ITER_LEV(hash)++;
00207 arg.hash = hash;
00208 arg.func = (rb_foreach_func *)func;
00209 arg.arg = farg;
00210 rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
00211 }
00212
00213 static VALUE
00214 hash_alloc(VALUE klass)
00215 {
00216 NEWOBJ_OF(hash, struct RHash, klass, T_HASH);
00217
00218 RHASH_IFNONE(hash) = Qnil;
00219
00220 return (VALUE)hash;
00221 }
00222
00223 static VALUE
00224 empty_hash_alloc(VALUE klass)
00225 {
00226 if (RUBY_DTRACE_HASH_CREATE_ENABLED()) {
00227 RUBY_DTRACE_HASH_CREATE(0, rb_sourcefile(), rb_sourceline());
00228 }
00229
00230 return hash_alloc(klass);
00231 }
00232
00233 VALUE
00234 rb_hash_new(void)
00235 {
00236 return hash_alloc(rb_cHash);
00237 }
00238
00239 VALUE
00240 rb_hash_dup(VALUE hash)
00241 {
00242 NEWOBJ_OF(ret, struct RHash,
00243 rb_obj_class(hash),
00244 (RBASIC(hash)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED));
00245 if (FL_TEST((hash), FL_EXIVAR))
00246 rb_copy_generic_ivar((VALUE)(ret),(VALUE)(hash));
00247
00248 if (!RHASH_EMPTY_P(hash))
00249 ret->ntbl = st_copy(RHASH(hash)->ntbl);
00250 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00251 FL_SET(ret, HASH_PROC_DEFAULT);
00252 }
00253 RHASH_IFNONE(ret) = RHASH_IFNONE(hash);
00254 return (VALUE)ret;
00255 }
00256
00257 static void
00258 rb_hash_modify_check(VALUE hash)
00259 {
00260 rb_check_frozen(hash);
00261 if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4)
00262 rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
00263 }
00264
00265 struct st_table *
00266 rb_hash_tbl(VALUE hash)
00267 {
00268 if (!RHASH(hash)->ntbl) {
00269 RHASH(hash)->ntbl = st_init_table(&objhash);
00270 }
00271 return RHASH(hash)->ntbl;
00272 }
00273
00274 static void
00275 rb_hash_modify(VALUE hash)
00276 {
00277 rb_hash_modify_check(hash);
00278 rb_hash_tbl(hash);
00279 }
00280
00281 NORETURN(static void no_new_key(void));
00282 static void
00283 no_new_key(void)
00284 {
00285 rb_raise(rb_eRuntimeError, "can't add a new key into hash during iteration");
00286 }
00287
00288 #define NOINSERT_UPDATE_CALLBACK(func) \
00289 int \
00290 func##_noinsert(st_data_t *key, st_data_t *val, st_data_t arg, int existing) \
00291 { \
00292 if (!existing) no_new_key(); \
00293 return func(key, val, arg, existing); \
00294 }
00295
00296 #define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func)
00297
00298 #define RHASH_UPDATE_ITER(hash, iter_lev, key, func, arg) \
00299 st_update(RHASH(hash)->ntbl, (st_data_t)(key), \
00300 UPDATE_CALLBACK((iter_lev), func), \
00301 (st_data_t)(arg))
00302 #define RHASH_UPDATE(hash, key, func, arg) \
00303 RHASH_UPDATE_ITER(hash, RHASH_ITER_LEV(hash), key, func, arg)
00304
00305 static void
00306 default_proc_arity_check(VALUE proc)
00307 {
00308 int n = rb_proc_arity(proc);
00309
00310 if (rb_proc_lambda_p(proc) && n != 2 && (n >= 0 || n < -3)) {
00311 if (n < 0) n = -n-1;
00312 rb_raise(rb_eTypeError, "default_proc takes two arguments (2 for %d)", n);
00313 }
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 static VALUE
00352 rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
00353 {
00354 VALUE ifnone;
00355
00356 rb_hash_modify(hash);
00357 if (rb_block_given_p()) {
00358 rb_check_arity(argc, 0, 0);
00359 ifnone = rb_block_proc();
00360 default_proc_arity_check(ifnone);
00361 RHASH_IFNONE(hash) = ifnone;
00362 FL_SET(hash, HASH_PROC_DEFAULT);
00363 }
00364 else {
00365 rb_scan_args(argc, argv, "01", &ifnone);
00366 RHASH_IFNONE(hash) = ifnone;
00367 }
00368
00369 return hash;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 static VALUE
00390 rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
00391 {
00392 VALUE hash, tmp;
00393 int i;
00394
00395 if (argc == 1) {
00396 tmp = rb_hash_s_try_convert(Qnil, argv[0]);
00397 if (!NIL_P(tmp)) {
00398 hash = hash_alloc(klass);
00399 if (RHASH(tmp)->ntbl) {
00400 RHASH(hash)->ntbl = st_copy(RHASH(tmp)->ntbl);
00401 }
00402 return hash;
00403 }
00404
00405 tmp = rb_check_array_type(argv[0]);
00406 if (!NIL_P(tmp)) {
00407 long i;
00408
00409 hash = hash_alloc(klass);
00410 for (i = 0; i < RARRAY_LEN(tmp); ++i) {
00411 VALUE e = RARRAY_PTR(tmp)[i];
00412 VALUE v = rb_check_array_type(e);
00413 VALUE key, val = Qnil;
00414
00415 if (NIL_P(v)) {
00416 #if 0
00417 rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
00418 rb_builtin_class_name(e), i);
00419
00420 #else
00421 rb_warn("wrong element type %s at %ld (expected array)",
00422 rb_builtin_class_name(e), i);
00423 rb_warn("ignoring wrong elements is deprecated, remove them explicitly");
00424 rb_warn("this causes ArgumentError in the next release");
00425 continue;
00426 #endif
00427 }
00428 switch (RARRAY_LEN(v)) {
00429 default:
00430 rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
00431 RARRAY_LEN(v));
00432 case 2:
00433 val = RARRAY_PTR(v)[1];
00434 case 1:
00435 key = RARRAY_PTR(v)[0];
00436 rb_hash_aset(hash, key, val);
00437 }
00438 }
00439 return hash;
00440 }
00441 }
00442 if (argc % 2 != 0) {
00443 rb_raise(rb_eArgError, "odd number of arguments for Hash");
00444 }
00445
00446 hash = hash_alloc(klass);
00447 for (i=0; i<argc; i+=2) {
00448 rb_hash_aset(hash, argv[i], argv[i + 1]);
00449 }
00450
00451 return hash;
00452 }
00453
00454 static VALUE
00455 to_hash(VALUE hash)
00456 {
00457 return rb_convert_type(hash, T_HASH, "Hash", "to_hash");
00458 }
00459
00460 VALUE
00461 rb_check_hash_type(VALUE hash)
00462 {
00463 return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 static VALUE
00478 rb_hash_s_try_convert(VALUE dummy, VALUE hash)
00479 {
00480 return rb_check_hash_type(hash);
00481 }
00482
00483 struct rehash_arg {
00484 VALUE hash;
00485 st_table *tbl;
00486 };
00487
00488 static int
00489 rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
00490 {
00491 st_table *tbl = (st_table *)arg;
00492
00493 st_insert(tbl, (st_data_t)key, (st_data_t)value);
00494 return ST_CONTINUE;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517 static VALUE
00518 rb_hash_rehash(VALUE hash)
00519 {
00520 VALUE tmp;
00521 st_table *tbl;
00522
00523 if (RHASH_ITER_LEV(hash) > 0) {
00524 rb_raise(rb_eRuntimeError, "rehash during iteration");
00525 }
00526 rb_hash_modify_check(hash);
00527 if (!RHASH(hash)->ntbl)
00528 return hash;
00529 tmp = hash_alloc(0);
00530 tbl = st_init_table_with_size(RHASH(hash)->ntbl->type, RHASH(hash)->ntbl->num_entries);
00531 RHASH(tmp)->ntbl = tbl;
00532
00533 rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
00534 st_free_table(RHASH(hash)->ntbl);
00535 RHASH(hash)->ntbl = tbl;
00536 RHASH(tmp)->ntbl = 0;
00537
00538 return hash;
00539 }
00540
00541 static VALUE
00542 hash_default_value(VALUE hash, VALUE key)
00543 {
00544 if (rb_method_basic_definition_p(CLASS_OF(hash), id_default)) {
00545 VALUE ifnone = RHASH_IFNONE(hash);
00546 if (!FL_TEST(hash, HASH_PROC_DEFAULT)) return ifnone;
00547 if (key == Qundef) return Qnil;
00548 return rb_funcall(ifnone, id_yield, 2, hash, key);
00549 }
00550 else {
00551 return rb_funcall(hash, id_default, 1, key);
00552 }
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 VALUE
00570 rb_hash_aref(VALUE hash, VALUE key)
00571 {
00572 st_data_t val;
00573
00574 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00575 return hash_default_value(hash, key);
00576 }
00577 return (VALUE)val;
00578 }
00579
00580 VALUE
00581 rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
00582 {
00583 st_data_t val;
00584
00585 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00586 return def;
00587 }
00588 return (VALUE)val;
00589 }
00590
00591 VALUE
00592 rb_hash_lookup(VALUE hash, VALUE key)
00593 {
00594 return rb_hash_lookup2(hash, key, Qnil);
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 static VALUE
00627 rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash)
00628 {
00629 VALUE key, if_none;
00630 st_data_t val;
00631 long block_given;
00632
00633 rb_scan_args(argc, argv, "11", &key, &if_none);
00634
00635 block_given = rb_block_given_p();
00636 if (block_given && argc == 2) {
00637 rb_warn("block supersedes default value argument");
00638 }
00639 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00640 if (block_given) return rb_yield(key);
00641 if (argc == 1) {
00642 volatile VALUE desc = rb_protect(rb_inspect, key, 0);
00643 if (NIL_P(desc)) {
00644 desc = rb_any_to_s(key);
00645 }
00646 desc = rb_str_ellipsize(desc, 65);
00647 rb_raise(rb_eKeyError, "key not found: %s", RSTRING_PTR(desc));
00648 }
00649 return if_none;
00650 }
00651 return (VALUE)val;
00652 }
00653
00654 VALUE
00655 rb_hash_fetch(VALUE hash, VALUE key)
00656 {
00657 return rb_hash_fetch_m(1, &key, hash);
00658 }
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 static VALUE
00682 rb_hash_default(int argc, VALUE *argv, VALUE hash)
00683 {
00684 VALUE key, ifnone;
00685
00686 rb_scan_args(argc, argv, "01", &key);
00687 ifnone = RHASH_IFNONE(hash);
00688 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00689 if (argc == 0) return Qnil;
00690 return rb_funcall(ifnone, id_yield, 2, hash, key);
00691 }
00692 return ifnone;
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 static VALUE
00716 rb_hash_set_default(VALUE hash, VALUE ifnone)
00717 {
00718 rb_hash_modify_check(hash);
00719 RHASH_IFNONE(hash) = ifnone;
00720 FL_UNSET(hash, HASH_PROC_DEFAULT);
00721 return ifnone;
00722 }
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739 static VALUE
00740 rb_hash_default_proc(VALUE hash)
00741 {
00742 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00743 return RHASH_IFNONE(hash);
00744 }
00745 return Qnil;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 static VALUE
00762 rb_hash_set_default_proc(VALUE hash, VALUE proc)
00763 {
00764 VALUE b;
00765
00766 rb_hash_modify_check(hash);
00767 if (NIL_P(proc)) {
00768 FL_UNSET(hash, HASH_PROC_DEFAULT);
00769 RHASH_IFNONE(hash) = proc;
00770 return proc;
00771 }
00772 b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
00773 if (NIL_P(b) || !rb_obj_is_proc(b)) {
00774 rb_raise(rb_eTypeError,
00775 "wrong default_proc type %s (expected Proc)",
00776 rb_obj_classname(proc));
00777 }
00778 proc = b;
00779 default_proc_arity_check(proc);
00780 RHASH_IFNONE(hash) = proc;
00781 FL_SET(hash, HASH_PROC_DEFAULT);
00782 return proc;
00783 }
00784
00785 static int
00786 key_i(VALUE key, VALUE value, VALUE arg)
00787 {
00788 VALUE *args = (VALUE *)arg;
00789
00790 if (rb_equal(value, args[0])) {
00791 args[1] = key;
00792 return ST_STOP;
00793 }
00794 return ST_CONTINUE;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 static VALUE
00812 rb_hash_key(VALUE hash, VALUE value)
00813 {
00814 VALUE args[2];
00815
00816 args[0] = value;
00817 args[1] = Qnil;
00818
00819 rb_hash_foreach(hash, key_i, (VALUE)args);
00820
00821 return args[1];
00822 }
00823
00824
00825 static VALUE
00826 rb_hash_index(VALUE hash, VALUE value)
00827 {
00828 rb_warn("Hash#index is deprecated; use Hash#key");
00829 return rb_hash_key(hash, value);
00830 }
00831
00832 static VALUE
00833 rb_hash_delete_key(VALUE hash, VALUE key)
00834 {
00835 st_data_t ktmp = (st_data_t)key, val;
00836
00837 if (!RHASH(hash)->ntbl)
00838 return Qundef;
00839 if (RHASH_ITER_LEV(hash) > 0) {
00840 if (st_delete_safe(RHASH(hash)->ntbl, &ktmp, &val, (st_data_t)Qundef)) {
00841 FL_SET(hash, HASH_DELETED);
00842 return (VALUE)val;
00843 }
00844 }
00845 else if (st_delete(RHASH(hash)->ntbl, &ktmp, &val))
00846 return (VALUE)val;
00847 return Qundef;
00848 }
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868 VALUE
00869 rb_hash_delete(VALUE hash, VALUE key)
00870 {
00871 VALUE val;
00872
00873 rb_hash_modify_check(hash);
00874 val = rb_hash_delete_key(hash, key);
00875 if (val != Qundef) return val;
00876 if (rb_block_given_p()) {
00877 return rb_yield(key);
00878 }
00879 return Qnil;
00880 }
00881
00882 struct shift_var {
00883 VALUE key;
00884 VALUE val;
00885 };
00886
00887 static int
00888 shift_i(VALUE key, VALUE value, VALUE arg)
00889 {
00890 struct shift_var *var = (struct shift_var *)arg;
00891
00892 if (var->key != Qundef) return ST_STOP;
00893 var->key = key;
00894 var->val = value;
00895 return ST_DELETE;
00896 }
00897
00898 static int
00899 shift_i_safe(VALUE key, VALUE value, VALUE arg)
00900 {
00901 struct shift_var *var = (struct shift_var *)arg;
00902
00903 var->key = key;
00904 var->val = value;
00905 return ST_STOP;
00906 }
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921 static VALUE
00922 rb_hash_shift(VALUE hash)
00923 {
00924 struct shift_var var;
00925
00926 rb_hash_modify_check(hash);
00927 if (RHASH(hash)->ntbl) {
00928 var.key = Qundef;
00929 rb_hash_foreach(hash, RHASH_ITER_LEV(hash) > 0 ? shift_i_safe : shift_i,
00930 (VALUE)&var);
00931
00932 if (var.key != Qundef) {
00933 if (RHASH_ITER_LEV(hash) > 0) {
00934 rb_hash_delete_key(hash, var.key);
00935 }
00936 return rb_assoc_new(var.key, var.val);
00937 }
00938 }
00939 return hash_default_value(hash, Qnil);
00940 }
00941
00942 static int
00943 delete_if_i(VALUE key, VALUE value, VALUE hash)
00944 {
00945 if (RTEST(rb_yield_values(2, key, value))) {
00946 rb_hash_delete_key(hash, key);
00947 }
00948 return ST_CONTINUE;
00949 }
00950
00951 static VALUE rb_hash_size(VALUE hash);
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968 VALUE
00969 rb_hash_delete_if(VALUE hash)
00970 {
00971 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
00972 rb_hash_modify_check(hash);
00973 if (RHASH(hash)->ntbl)
00974 rb_hash_foreach(hash, delete_if_i, hash);
00975 return hash;
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987 VALUE
00988 rb_hash_reject_bang(VALUE hash)
00989 {
00990 st_index_t n;
00991
00992 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
00993 rb_hash_modify(hash);
00994 if (!RHASH(hash)->ntbl)
00995 return Qnil;
00996 n = RHASH(hash)->ntbl->num_entries;
00997 rb_hash_foreach(hash, delete_if_i, hash);
00998 if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
00999 return hash;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 static VALUE
01014 rb_hash_reject(VALUE hash)
01015 {
01016 return rb_hash_delete_if(rb_obj_dup(hash));
01017 }
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 VALUE
01031 rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
01032 {
01033 VALUE result = rb_ary_new2(argc);
01034 long i;
01035
01036 for (i=0; i<argc; i++) {
01037 rb_ary_push(result, rb_hash_aref(hash, argv[i]));
01038 }
01039 return result;
01040 }
01041
01042 static int
01043 select_i(VALUE key, VALUE value, VALUE result)
01044 {
01045 if (RTEST(rb_yield_values(2, key, value)))
01046 rb_hash_aset(result, key, value);
01047 return ST_CONTINUE;
01048 }
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064 VALUE
01065 rb_hash_select(VALUE hash)
01066 {
01067 VALUE result;
01068
01069 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01070 result = rb_hash_new();
01071 rb_hash_foreach(hash, select_i, result);
01072 return result;
01073 }
01074
01075 static int
01076 keep_if_i(VALUE key, VALUE value, VALUE hash)
01077 {
01078 if (!RTEST(rb_yield_values(2, key, value))) {
01079 return ST_DELETE;
01080 }
01081 return ST_CONTINUE;
01082 }
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093 VALUE
01094 rb_hash_select_bang(VALUE hash)
01095 {
01096 st_index_t n;
01097
01098 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01099 rb_hash_modify_check(hash);
01100 if (!RHASH(hash)->ntbl)
01101 return Qnil;
01102 n = RHASH(hash)->ntbl->num_entries;
01103 rb_hash_foreach(hash, keep_if_i, hash);
01104 if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
01105 return hash;
01106 }
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120 VALUE
01121 rb_hash_keep_if(VALUE hash)
01122 {
01123 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01124 rb_hash_modify_check(hash);
01125 if (RHASH(hash)->ntbl)
01126 rb_hash_foreach(hash, keep_if_i, hash);
01127 return hash;
01128 }
01129
01130 static int
01131 clear_i(VALUE key, VALUE value, VALUE dummy)
01132 {
01133 return ST_DELETE;
01134 }
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147 VALUE
01148 rb_hash_clear(VALUE hash)
01149 {
01150 rb_hash_modify_check(hash);
01151 if (!RHASH(hash)->ntbl)
01152 return hash;
01153 if (RHASH(hash)->ntbl->num_entries > 0) {
01154 if (RHASH_ITER_LEV(hash) > 0)
01155 rb_hash_foreach(hash, clear_i, 0);
01156 else
01157 st_clear(RHASH(hash)->ntbl);
01158 }
01159
01160 return hash;
01161 }
01162
01163 static int
01164 hash_aset(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
01165 {
01166 *val = arg;
01167 return ST_CONTINUE;
01168 }
01169
01170 static int
01171 hash_aset_str(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
01172 {
01173 *key = (st_data_t)rb_str_new_frozen((VALUE)*key);
01174 return hash_aset(key, val, arg, existing);
01175 }
01176
01177 static NOINSERT_UPDATE_CALLBACK(hash_aset)
01178 static NOINSERT_UPDATE_CALLBACK(hash_aset_str)
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205 VALUE
01206 rb_hash_aset(VALUE hash, VALUE key, VALUE val)
01207 {
01208 int iter_lev = RHASH_ITER_LEV(hash);
01209 st_table *tbl = RHASH(hash)->ntbl;
01210
01211 rb_hash_modify(hash);
01212 if (!tbl) {
01213 if (iter_lev > 0) no_new_key();
01214 tbl = RHASH_TBL(hash);
01215 }
01216 if (tbl->type == &identhash || rb_obj_class(key) != rb_cString) {
01217 RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
01218 }
01219 else {
01220 RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
01221 }
01222 return val;
01223 }
01224
01225 static int
01226 replace_i(VALUE key, VALUE val, VALUE hash)
01227 {
01228 rb_hash_aset(hash, key, val);
01229
01230 return ST_CONTINUE;
01231 }
01232
01233 static VALUE
01234 rb_hash_initialize_copy(VALUE hash, VALUE hash2)
01235 {
01236 st_table *ntbl;
01237
01238 rb_hash_modify_check(hash);
01239 hash2 = to_hash(hash2);
01240
01241 Check_Type(hash2, T_HASH);
01242
01243 if (hash == hash2) return hash;
01244
01245 ntbl = RHASH(hash)->ntbl;
01246 if (RHASH(hash2)->ntbl) {
01247 if (ntbl) st_free_table(ntbl);
01248 RHASH(hash)->ntbl = st_copy(RHASH(hash2)->ntbl);
01249 if (RHASH(hash)->ntbl->num_entries)
01250 rb_hash_rehash(hash);
01251 }
01252 else if (ntbl) {
01253 st_clear(ntbl);
01254 }
01255
01256 if (FL_TEST(hash2, HASH_PROC_DEFAULT)) {
01257 FL_SET(hash, HASH_PROC_DEFAULT);
01258 }
01259 else {
01260 FL_UNSET(hash, HASH_PROC_DEFAULT);
01261 }
01262 RHASH_IFNONE(hash) = RHASH_IFNONE(hash2);
01263
01264 return hash;
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279 static VALUE
01280 rb_hash_replace(VALUE hash, VALUE hash2)
01281 {
01282 rb_hash_modify_check(hash);
01283 hash2 = to_hash(hash2);
01284 if (hash == hash2) return hash;
01285 rb_hash_clear(hash);
01286 if (RHASH(hash2)->ntbl) {
01287 rb_hash_tbl(hash);
01288 RHASH(hash)->ntbl->type = RHASH(hash2)->ntbl->type;
01289 }
01290 rb_hash_foreach(hash2, replace_i, hash);
01291 RHASH_IFNONE(hash) = RHASH_IFNONE(hash2);
01292 if (FL_TEST(hash2, HASH_PROC_DEFAULT)) {
01293 FL_SET(hash, HASH_PROC_DEFAULT);
01294 }
01295 else {
01296 FL_UNSET(hash, HASH_PROC_DEFAULT);
01297 }
01298
01299 return hash;
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315 static VALUE
01316 rb_hash_size(VALUE hash)
01317 {
01318 if (!RHASH(hash)->ntbl)
01319 return INT2FIX(0);
01320 return INT2FIX(RHASH(hash)->ntbl->num_entries);
01321 }
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334 static VALUE
01335 rb_hash_empty_p(VALUE hash)
01336 {
01337 return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
01338 }
01339
01340 static int
01341 each_value_i(VALUE key, VALUE value)
01342 {
01343 rb_yield(value);
01344 return ST_CONTINUE;
01345 }
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366 static VALUE
01367 rb_hash_each_value(VALUE hash)
01368 {
01369 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01370 rb_hash_foreach(hash, each_value_i, 0);
01371 return hash;
01372 }
01373
01374 static int
01375 each_key_i(VALUE key, VALUE value)
01376 {
01377 rb_yield(key);
01378 return ST_CONTINUE;
01379 }
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399 static VALUE
01400 rb_hash_each_key(VALUE hash)
01401 {
01402 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01403 rb_hash_foreach(hash, each_key_i, 0);
01404 return hash;
01405 }
01406
01407 static int
01408 each_pair_i(VALUE key, VALUE value)
01409 {
01410 rb_yield(rb_assoc_new(key, value));
01411 return ST_CONTINUE;
01412 }
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436 static VALUE
01437 rb_hash_each_pair(VALUE hash)
01438 {
01439 RETURN_SIZED_ENUMERATOR(hash, 0, 0, rb_hash_size);
01440 rb_hash_foreach(hash, each_pair_i, 0);
01441 return hash;
01442 }
01443
01444 static int
01445 to_a_i(VALUE key, VALUE value, VALUE ary)
01446 {
01447 rb_ary_push(ary, rb_assoc_new(key, value));
01448 return ST_CONTINUE;
01449 }
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462 static VALUE
01463 rb_hash_to_a(VALUE hash)
01464 {
01465 VALUE ary;
01466
01467 ary = rb_ary_new();
01468 rb_hash_foreach(hash, to_a_i, ary);
01469 OBJ_INFECT(ary, hash);
01470
01471 return ary;
01472 }
01473
01474 static int
01475 inspect_i(VALUE key, VALUE value, VALUE str)
01476 {
01477 VALUE str2;
01478
01479 str2 = rb_inspect(key);
01480 if (RSTRING_LEN(str) > 1) {
01481 rb_str_buf_cat_ascii(str, ", ");
01482 }
01483 else {
01484 rb_enc_copy(str, str2);
01485 }
01486 rb_str_buf_append(str, str2);
01487 OBJ_INFECT(str, str2);
01488 rb_str_buf_cat_ascii(str, "=>");
01489 str2 = rb_inspect(value);
01490 rb_str_buf_append(str, str2);
01491 OBJ_INFECT(str, str2);
01492
01493 return ST_CONTINUE;
01494 }
01495
01496 static VALUE
01497 inspect_hash(VALUE hash, VALUE dummy, int recur)
01498 {
01499 VALUE str;
01500
01501 if (recur) return rb_usascii_str_new2("{...}");
01502 str = rb_str_buf_new2("{");
01503 rb_hash_foreach(hash, inspect_i, str);
01504 rb_str_buf_cat2(str, "}");
01505 OBJ_INFECT(str, hash);
01506
01507 return str;
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521 static VALUE
01522 rb_hash_inspect(VALUE hash)
01523 {
01524 if (RHASH_EMPTY_P(hash))
01525 return rb_usascii_str_new2("{}");
01526 return rb_exec_recursive(inspect_hash, hash, 0);
01527 }
01528
01529
01530
01531
01532
01533
01534
01535
01536 static VALUE
01537 rb_hash_to_hash(VALUE hash)
01538 {
01539 return hash;
01540 }
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550 static VALUE
01551 rb_hash_to_h(VALUE hash)
01552 {
01553 if (rb_obj_class(hash) != rb_cHash) {
01554 VALUE ret = rb_hash_new();
01555 if (!RHASH_EMPTY_P(hash))
01556 RHASH(ret)->ntbl = st_copy(RHASH(hash)->ntbl);
01557 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
01558 FL_SET(ret, HASH_PROC_DEFAULT);
01559 }
01560 RHASH_IFNONE(ret) = RHASH_IFNONE(hash);
01561 return ret;
01562 }
01563 return hash;
01564 }
01565
01566 static int
01567 keys_i(VALUE key, VALUE value, VALUE ary)
01568 {
01569 rb_ary_push(ary, key);
01570 return ST_CONTINUE;
01571 }
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585 static VALUE
01586 rb_hash_keys(VALUE hash)
01587 {
01588 VALUE ary;
01589
01590 ary = rb_ary_new();
01591 rb_hash_foreach(hash, keys_i, ary);
01592
01593 return ary;
01594 }
01595
01596 static int
01597 values_i(VALUE key, VALUE value, VALUE ary)
01598 {
01599 rb_ary_push(ary, value);
01600 return ST_CONTINUE;
01601 }
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615 static VALUE
01616 rb_hash_values(VALUE hash)
01617 {
01618 VALUE ary;
01619
01620 ary = rb_ary_new();
01621 rb_hash_foreach(hash, values_i, ary);
01622
01623 return ary;
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641 static VALUE
01642 rb_hash_has_key(VALUE hash, VALUE key)
01643 {
01644 if (!RHASH(hash)->ntbl)
01645 return Qfalse;
01646 if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
01647 return Qtrue;
01648 }
01649 return Qfalse;
01650 }
01651
01652 static int
01653 rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
01654 {
01655 VALUE *data = (VALUE *)arg;
01656
01657 if (rb_equal(value, data[1])) {
01658 data[0] = Qtrue;
01659 return ST_STOP;
01660 }
01661 return ST_CONTINUE;
01662 }
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 static VALUE
01678 rb_hash_has_value(VALUE hash, VALUE val)
01679 {
01680 VALUE data[2];
01681
01682 data[0] = Qfalse;
01683 data[1] = val;
01684 rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
01685 return data[0];
01686 }
01687
01688 struct equal_data {
01689 VALUE result;
01690 st_table *tbl;
01691 int eql;
01692 };
01693
01694 static int
01695 eql_i(VALUE key, VALUE val1, VALUE arg)
01696 {
01697 struct equal_data *data = (struct equal_data *)arg;
01698 st_data_t val2;
01699
01700 if (!st_lookup(data->tbl, key, &val2)) {
01701 data->result = Qfalse;
01702 return ST_STOP;
01703 }
01704 if (!(data->eql ? rb_eql(val1, (VALUE)val2) : (int)rb_equal(val1, (VALUE)val2))) {
01705 data->result = Qfalse;
01706 return ST_STOP;
01707 }
01708 return ST_CONTINUE;
01709 }
01710
01711 static VALUE
01712 recursive_eql(VALUE hash, VALUE dt, int recur)
01713 {
01714 struct equal_data *data;
01715
01716 if (recur) return Qtrue;
01717 data = (struct equal_data*)dt;
01718 data->result = Qtrue;
01719 rb_hash_foreach(hash, eql_i, dt);
01720
01721 return data->result;
01722 }
01723
01724 static VALUE
01725 hash_equal(VALUE hash1, VALUE hash2, int eql)
01726 {
01727 struct equal_data data;
01728
01729 if (hash1 == hash2) return Qtrue;
01730 if (!RB_TYPE_P(hash2, T_HASH)) {
01731 if (!rb_respond_to(hash2, rb_intern("to_hash"))) {
01732 return Qfalse;
01733 }
01734 if (eql)
01735 return rb_eql(hash2, hash1);
01736 else
01737 return rb_equal(hash2, hash1);
01738 }
01739 if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2))
01740 return Qfalse;
01741 if (!RHASH(hash1)->ntbl || !RHASH(hash2)->ntbl)
01742 return Qtrue;
01743 if (RHASH(hash1)->ntbl->type != RHASH(hash2)->ntbl->type)
01744 return Qfalse;
01745 #if 0
01746 if (!(rb_equal(RHASH_IFNONE(hash1), RHASH_IFNONE(hash2)) &&
01747 FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT)))
01748 return Qfalse;
01749 #endif
01750
01751 data.tbl = RHASH(hash2)->ntbl;
01752 data.eql = eql;
01753 return rb_exec_recursive_paired(recursive_eql, hash1, hash2, (VALUE)&data);
01754 }
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775 static VALUE
01776 rb_hash_equal(VALUE hash1, VALUE hash2)
01777 {
01778 return hash_equal(hash1, hash2, FALSE);
01779 }
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789 static VALUE
01790 rb_hash_eql(VALUE hash1, VALUE hash2)
01791 {
01792 return hash_equal(hash1, hash2, TRUE);
01793 }
01794
01795 static int
01796 hash_i(VALUE key, VALUE val, VALUE arg)
01797 {
01798 st_index_t *hval = (st_index_t *)arg;
01799 st_index_t hdata[2];
01800
01801 hdata[0] = rb_hash(key);
01802 hdata[1] = rb_hash(val);
01803 *hval ^= st_hash(hdata, sizeof(hdata), 0);
01804 return ST_CONTINUE;
01805 }
01806
01807 static VALUE
01808 recursive_hash(VALUE hash, VALUE dummy, int recur)
01809 {
01810 st_index_t hval;
01811
01812 if (!RHASH(hash)->ntbl)
01813 return LONG2FIX(0);
01814 hval = RHASH(hash)->ntbl->num_entries;
01815 if (!hval) return LONG2FIX(0);
01816 if (recur)
01817 hval = rb_hash_uint(rb_hash_start(rb_hash(rb_cHash)), hval);
01818 else
01819 rb_hash_foreach(hash, hash_i, (VALUE)&hval);
01820 hval = rb_hash_end(hval);
01821 return INT2FIX(hval);
01822 }
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832 static VALUE
01833 rb_hash_hash(VALUE hash)
01834 {
01835 return rb_exec_recursive_outer(recursive_hash, hash, 0);
01836 }
01837
01838 static int
01839 rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
01840 {
01841 rb_hash_aset(hash, value, key);
01842 return ST_CONTINUE;
01843 }
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857 static VALUE
01858 rb_hash_invert(VALUE hash)
01859 {
01860 VALUE h = rb_hash_new();
01861
01862 rb_hash_foreach(hash, rb_hash_invert_i, h);
01863 return h;
01864 }
01865
01866 static int
01867 rb_hash_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
01868 {
01869 *value = arg;
01870 return ST_CONTINUE;
01871 }
01872
01873 static NOINSERT_UPDATE_CALLBACK(rb_hash_update_callback)
01874
01875 static int
01876 rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
01877 {
01878 RHASH_UPDATE(hash, key, rb_hash_update_callback, value);
01879 return ST_CONTINUE;
01880 }
01881
01882 static int
01883 rb_hash_update_block_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
01884 {
01885 VALUE newvalue = (VALUE)arg;
01886 if (existing) {
01887 newvalue = rb_yield_values(3, (VALUE)*key, (VALUE)*value, newvalue);
01888 }
01889 *value = (st_data_t)newvalue;
01890 return ST_CONTINUE;
01891 }
01892
01893 static NOINSERT_UPDATE_CALLBACK(rb_hash_update_block_callback)
01894
01895 static int
01896 rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
01897 {
01898 RHASH_UPDATE(hash, key, rb_hash_update_block_callback, value);
01899 return ST_CONTINUE;
01900 }
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925 static VALUE
01926 rb_hash_update(VALUE hash1, VALUE hash2)
01927 {
01928 rb_hash_modify(hash1);
01929 hash2 = to_hash(hash2);
01930 if (rb_block_given_p()) {
01931 rb_hash_foreach(hash2, rb_hash_update_block_i, hash1);
01932 }
01933 else {
01934 rb_hash_foreach(hash2, rb_hash_update_i, hash1);
01935 }
01936 return hash1;
01937 }
01938
01939 struct update_arg {
01940 VALUE hash;
01941 VALUE value;
01942 rb_hash_update_func *func;
01943 };
01944
01945 static int
01946 rb_hash_update_func_callback(st_data_t *key, st_data_t *value, st_data_t arg0, int existing)
01947 {
01948 struct update_arg *arg = (struct update_arg *)arg0;
01949 VALUE newvalue = arg->value;
01950 if (existing) {
01951 newvalue = (*arg->func)((VALUE)*key, (VALUE)*value, newvalue);
01952 }
01953 *value = (st_data_t)newvalue;
01954 return ST_CONTINUE;
01955 }
01956
01957 static NOINSERT_UPDATE_CALLBACK(rb_hash_update_func_callback)
01958
01959 static int
01960 rb_hash_update_func_i(VALUE key, VALUE value, VALUE arg0)
01961 {
01962 struct update_arg *arg = (struct update_arg *)arg0;
01963 VALUE hash = arg->hash;
01964
01965 arg->value = value;
01966 RHASH_UPDATE(hash, key, rb_hash_update_func_callback, arg);
01967 return ST_CONTINUE;
01968 }
01969
01970 VALUE
01971 rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func)
01972 {
01973 rb_hash_modify(hash1);
01974 hash2 = to_hash(hash2);
01975 if (func) {
01976 struct update_arg arg;
01977 arg.hash = hash1;
01978 arg.func = func;
01979 rb_hash_foreach(hash2, rb_hash_update_func_i, (VALUE)&arg);
01980 }
01981 else {
01982 rb_hash_foreach(hash2, rb_hash_update_i, hash1);
01983 }
01984 return hash1;
01985 }
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007 static VALUE
02008 rb_hash_merge(VALUE hash1, VALUE hash2)
02009 {
02010 return rb_hash_update(rb_obj_dup(hash1), hash2);
02011 }
02012
02013 static int
02014 assoc_i(VALUE key, VALUE val, VALUE arg)
02015 {
02016 VALUE *args = (VALUE *)arg;
02017
02018 if (RTEST(rb_equal(args[0], key))) {
02019 args[1] = rb_assoc_new(key, val);
02020 return ST_STOP;
02021 }
02022 return ST_CONTINUE;
02023 }
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039 VALUE
02040 rb_hash_assoc(VALUE hash, VALUE obj)
02041 {
02042 VALUE args[2];
02043
02044 args[0] = obj;
02045 args[1] = Qnil;
02046 rb_hash_foreach(hash, assoc_i, (VALUE)args);
02047 return args[1];
02048 }
02049
02050 static int
02051 rassoc_i(VALUE key, VALUE val, VALUE arg)
02052 {
02053 VALUE *args = (VALUE *)arg;
02054
02055 if (RTEST(rb_equal(args[0], val))) {
02056 args[1] = rb_assoc_new(key, val);
02057 return ST_STOP;
02058 }
02059 return ST_CONTINUE;
02060 }
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075 VALUE
02076 rb_hash_rassoc(VALUE hash, VALUE obj)
02077 {
02078 VALUE args[2];
02079
02080 args[0] = obj;
02081 args[1] = Qnil;
02082 rb_hash_foreach(hash, rassoc_i, (VALUE)args);
02083 return args[1];
02084 }
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102 static VALUE
02103 rb_hash_flatten(int argc, VALUE *argv, VALUE hash)
02104 {
02105 VALUE ary, tmp;
02106
02107 ary = rb_hash_to_a(hash);
02108 if (argc == 0) {
02109 argc = 1;
02110 tmp = INT2FIX(1);
02111 argv = &tmp;
02112 }
02113 rb_funcall2(ary, rb_intern("flatten!"), argc, argv);
02114 return ary;
02115 }
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133 static VALUE
02134 rb_hash_compare_by_id(VALUE hash)
02135 {
02136 rb_hash_modify(hash);
02137 RHASH(hash)->ntbl->type = &identhash;
02138 rb_hash_rehash(hash);
02139 return hash;
02140 }
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151 static VALUE
02152 rb_hash_compare_by_id_p(VALUE hash)
02153 {
02154 if (!RHASH(hash)->ntbl)
02155 return Qfalse;
02156 if (RHASH(hash)->ntbl->type == &identhash) {
02157 return Qtrue;
02158 }
02159 return Qfalse;
02160 }
02161
02162 static int path_tainted = -1;
02163
02164 static char **origenviron;
02165 #ifdef _WIN32
02166 #define GET_ENVIRON(e) ((e) = rb_w32_get_environ())
02167 #define FREE_ENVIRON(e) rb_w32_free_environ(e)
02168 static char **my_environ;
02169 #undef environ
02170 #define environ my_environ
02171 #undef getenv
02172 #define getenv(n) rb_w32_ugetenv(n)
02173 #elif defined(__APPLE__)
02174 #undef environ
02175 #define environ (*_NSGetEnviron())
02176 #define GET_ENVIRON(e) (e)
02177 #define FREE_ENVIRON(e)
02178 #else
02179 extern char **environ;
02180 #define GET_ENVIRON(e) (e)
02181 #define FREE_ENVIRON(e)
02182 #endif
02183 #ifdef ENV_IGNORECASE
02184 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
02185 #define ENVNMATCH(s1, s2, n) (STRNCASECMP((s1), (s2), (n)) == 0)
02186 #else
02187 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
02188 #define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
02189 #endif
02190
02191 static VALUE
02192 env_str_new(const char *ptr, long len)
02193 {
02194 #ifdef _WIN32
02195 VALUE str = rb_str_conv_enc(rb_str_new(ptr, len), rb_utf8_encoding(), rb_locale_encoding());
02196 #else
02197 VALUE str = rb_locale_str_new(ptr, len);
02198 #endif
02199
02200 rb_obj_freeze(str);
02201 return str;
02202 }
02203
02204 static VALUE
02205 env_str_new2(const char *ptr)
02206 {
02207 if (!ptr) return Qnil;
02208 return env_str_new(ptr, strlen(ptr));
02209 }
02210
02211 static VALUE
02212 env_delete(VALUE obj, VALUE name)
02213 {
02214 char *nam, *val;
02215
02216 rb_secure(4);
02217 SafeStringValue(name);
02218 nam = RSTRING_PTR(name);
02219 if (memchr(nam, '\0', RSTRING_LEN(name))) {
02220 rb_raise(rb_eArgError, "bad environment variable name");
02221 }
02222 val = getenv(nam);
02223 if (val) {
02224 VALUE value = env_str_new2(val);
02225
02226 ruby_setenv(nam, 0);
02227 if (ENVMATCH(nam, PATH_ENV)) {
02228 path_tainted = 0;
02229 }
02230 return value;
02231 }
02232 return Qnil;
02233 }
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244 static VALUE
02245 env_delete_m(VALUE obj, VALUE name)
02246 {
02247 VALUE val;
02248
02249 val = env_delete(obj, name);
02250 if (NIL_P(val) && rb_block_given_p()) rb_yield(name);
02251 return val;
02252 }
02253
02254 static int env_path_tainted(const char *);
02255
02256
02257
02258
02259
02260
02261
02262
02263 static VALUE
02264 rb_f_getenv(VALUE obj, VALUE name)
02265 {
02266 char *nam, *env;
02267
02268 rb_secure(4);
02269 SafeStringValue(name);
02270 nam = RSTRING_PTR(name);
02271 if (memchr(nam, '\0', RSTRING_LEN(name))) {
02272 rb_raise(rb_eArgError, "bad environment variable name");
02273 }
02274 env = getenv(nam);
02275 if (env) {
02276 if (ENVMATCH(nam, PATH_ENV) && !env_path_tainted(env)) {
02277 #ifdef _WIN32
02278 VALUE str = rb_str_conv_enc(rb_str_new(env, strlen(env)), rb_utf8_encoding(), rb_filesystem_encoding());
02279 #else
02280 VALUE str = rb_filesystem_str_new_cstr(env);
02281 #endif
02282
02283 rb_obj_freeze(str);
02284 return str;
02285 }
02286 return env_str_new2(env);
02287 }
02288 return Qnil;
02289 }
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305 static VALUE
02306 env_fetch(int argc, VALUE *argv)
02307 {
02308 VALUE key, if_none;
02309 long block_given;
02310 char *nam, *env;
02311
02312 rb_secure(4);
02313 rb_scan_args(argc, argv, "11", &key, &if_none);
02314 block_given = rb_block_given_p();
02315 if (block_given && argc == 2) {
02316 rb_warn("block supersedes default value argument");
02317 }
02318 SafeStringValue(key);
02319 nam = RSTRING_PTR(key);
02320 if (memchr(nam, '\0', RSTRING_LEN(key))) {
02321 rb_raise(rb_eArgError, "bad environment variable name");
02322 }
02323 env = getenv(nam);
02324 if (!env) {
02325 if (block_given) return rb_yield(key);
02326 if (argc == 1) {
02327 rb_raise(rb_eKeyError, "key not found");
02328 }
02329 return if_none;
02330 }
02331 if (ENVMATCH(nam, PATH_ENV) && !env_path_tainted(env))
02332 #ifdef _WIN32
02333 return rb_str_conv_enc(rb_str_new(env, strlen(env)), rb_utf8_encoding(), rb_filesystem_encoding());
02334 #else
02335 return rb_filesystem_str_new_cstr(env);
02336 #endif
02337 return env_str_new2(env);
02338 }
02339
02340 static void
02341 path_tainted_p(const char *path)
02342 {
02343 path_tainted = rb_path_check(path)?0:1;
02344 }
02345
02346 static int
02347 env_path_tainted(const char *path)
02348 {
02349 if (path_tainted < 0) {
02350 path_tainted_p(path);
02351 }
02352 return path_tainted;
02353 }
02354
02355 int
02356 rb_env_path_tainted(void)
02357 {
02358 if (path_tainted < 0) {
02359 path_tainted_p(getenv(PATH_ENV));
02360 }
02361 return path_tainted;
02362 }
02363
02364 #if defined(_WIN32) || (defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
02365 #elif defined __sun
02366 static int
02367 in_origenv(const char *str)
02368 {
02369 char **env;
02370 for (env = origenviron; *env; ++env) {
02371 if (*env == str) return 1;
02372 }
02373 return 0;
02374 }
02375 #else
02376 static int
02377 envix(const char *nam)
02378 {
02379 register int i, len = strlen(nam);
02380 char **env;
02381
02382 env = GET_ENVIRON(environ);
02383 for (i = 0; env[i]; i++) {
02384 if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=')
02385 break;
02386 }
02387 FREE_ENVIRON(environ);
02388 return i;
02389 }
02390 #endif
02391
02392 #if defined(_WIN32)
02393 static size_t
02394 getenvsize(const char* p)
02395 {
02396 const char* porg = p;
02397 while (*p++) p += strlen(p) + 1;
02398 return p - porg + 1;
02399 }
02400 static size_t
02401 getenvblocksize()
02402 {
02403 return (rb_w32_osver() >= 5) ? 32767 : 5120;
02404 }
02405 #endif
02406
02407 void
02408 ruby_setenv(const char *name, const char *value)
02409 {
02410 #if defined(_WIN32)
02411 VALUE buf;
02412 int failed = 0;
02413 if (strchr(name, '=')) {
02414 fail:
02415 errno = EINVAL;
02416 rb_sys_fail("ruby_setenv");
02417 }
02418 if (value) {
02419 char* p = GetEnvironmentStringsA();
02420 size_t n;
02421 if (!p) goto fail;
02422 n = strlen(name) + 2 + strlen(value) + getenvsize(p);
02423 FreeEnvironmentStringsA(p);
02424 if (n >= getenvblocksize()) {
02425 goto fail;
02426 }
02427 buf = rb_sprintf("%s=%s", name, value);
02428 }
02429 else {
02430 buf = rb_sprintf("%s=", name);
02431 }
02432 failed = putenv(RSTRING_PTR(buf));
02433
02434
02435 rb_str_resize(buf, 0);
02436 if (!value || !*value) {
02437
02438 if (!SetEnvironmentVariable(name, value) &&
02439 GetLastError() != ERROR_ENVVAR_NOT_FOUND) goto fail;
02440 }
02441 if (failed) goto fail;
02442 #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
02443 #undef setenv
02444 #undef unsetenv
02445 if (value) {
02446 if (setenv(name, value, 1))
02447 rb_sys_fail("setenv");
02448 } else {
02449 #ifdef VOID_UNSETENV
02450 unsetenv(name);
02451 #else
02452 if (unsetenv(name))
02453 rb_sys_fail("unsetenv");
02454 #endif
02455 }
02456 #elif defined __sun
02457 size_t len;
02458 char **env_ptr, *str;
02459 if (strchr(name, '=')) {
02460 errno = EINVAL;
02461 rb_sys_fail("ruby_setenv");
02462 }
02463 len = strlen(name);
02464 for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
02465 if (!strncmp(str, name, len) && str[len] == '=') {
02466 if (!in_origenv(str)) free(str);
02467 while ((env_ptr[0] = env_ptr[1]) != 0) env_ptr++;
02468 break;
02469 }
02470 }
02471 if (value) {
02472 str = malloc(len += strlen(value) + 2);
02473 snprintf(str, len, "%s=%s", name, value);
02474 if (putenv(str))
02475 rb_sys_fail("putenv");
02476 }
02477 #else
02478 size_t len;
02479 int i;
02480 if (strchr(name, '=')) {
02481 errno = EINVAL;
02482 rb_sys_fail("ruby_setenv");
02483 }
02484 i=envix(name);
02485
02486 if (environ == origenviron) {
02487 int j;
02488 int max;
02489 char **tmpenv;
02490
02491 for (max = i; environ[max]; max++) ;
02492 tmpenv = ALLOC_N(char*, max+2);
02493 for (j=0; j<max; j++)
02494 tmpenv[j] = ruby_strdup(environ[j]);
02495 tmpenv[max] = 0;
02496 environ = tmpenv;
02497 }
02498 if (environ[i]) {
02499 char **envp = origenviron;
02500 while (*envp && *envp != environ[i]) envp++;
02501 if (!*envp)
02502 xfree(environ[i]);
02503 if (!value) {
02504 while (environ[i]) {
02505 environ[i] = environ[i+1];
02506 i++;
02507 }
02508 return;
02509 }
02510 }
02511 else {
02512 if (!value) return;
02513 REALLOC_N(environ, char*, i+2);
02514 environ[i+1] = 0;
02515 }
02516 len = strlen(name) + strlen(value) + 2;
02517 environ[i] = ALLOC_N(char, len);
02518 snprintf(environ[i],len,"%s=%s",name,value);
02519 #endif
02520 }
02521
02522 void
02523 ruby_unsetenv(const char *name)
02524 {
02525 ruby_setenv(name, 0);
02526 }
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537 static VALUE
02538 env_aset(VALUE obj, VALUE nm, VALUE val)
02539 {
02540 char *name, *value;
02541
02542 if (rb_safe_level() >= 4) {
02543 rb_raise(rb_eSecurityError, "can't change environment variable");
02544 }
02545
02546 if (NIL_P(val)) {
02547 env_delete(obj, nm);
02548 return Qnil;
02549 }
02550 SafeStringValue(nm);
02551 SafeStringValue(val);
02552 name = RSTRING_PTR(nm);
02553 value = RSTRING_PTR(val);
02554 if (memchr(name, '\0', RSTRING_LEN(nm)))
02555 rb_raise(rb_eArgError, "bad environment variable name");
02556 if (memchr(value, '\0', RSTRING_LEN(val)))
02557 rb_raise(rb_eArgError, "bad environment variable value");
02558
02559 ruby_setenv(name, value);
02560 if (ENVMATCH(name, PATH_ENV)) {
02561 if (OBJ_TAINTED(val)) {
02562
02563 path_tainted = 1;
02564 return val;
02565 }
02566 else {
02567 path_tainted_p(value);
02568 }
02569 }
02570 return val;
02571 }
02572
02573
02574
02575
02576
02577
02578
02579 static VALUE
02580 env_keys(void)
02581 {
02582 char **env;
02583 VALUE ary;
02584
02585 rb_secure(4);
02586 ary = rb_ary_new();
02587 env = GET_ENVIRON(environ);
02588 while (*env) {
02589 char *s = strchr(*env, '=');
02590 if (s) {
02591 rb_ary_push(ary, env_str_new(*env, s-*env));
02592 }
02593 env++;
02594 }
02595 FREE_ENVIRON(environ);
02596 return ary;
02597 }
02598
02599 static VALUE
02600 rb_env_size(VALUE ehash)
02601 {
02602 char **env;
02603 long cnt = 0;
02604
02605 rb_secure(4);
02606
02607 env = GET_ENVIRON(environ);
02608 for (; *env ; ++env) {
02609 if (strchr(*env, '=')) {
02610 cnt++;
02611 }
02612 }
02613 FREE_ENVIRON(environ);
02614 return LONG2FIX(cnt);
02615 }
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626 static VALUE
02627 env_each_key(VALUE ehash)
02628 {
02629 VALUE keys;
02630 long i;
02631
02632 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02633 keys = env_keys();
02634 for (i=0; i<RARRAY_LEN(keys); i++) {
02635 rb_yield(RARRAY_PTR(keys)[i]);
02636 }
02637 return ehash;
02638 }
02639
02640
02641
02642
02643
02644
02645
02646 static VALUE
02647 env_values(void)
02648 {
02649 VALUE ary;
02650 char **env;
02651
02652 rb_secure(4);
02653 ary = rb_ary_new();
02654 env = GET_ENVIRON(environ);
02655 while (*env) {
02656 char *s = strchr(*env, '=');
02657 if (s) {
02658 rb_ary_push(ary, env_str_new2(s+1));
02659 }
02660 env++;
02661 }
02662 FREE_ENVIRON(environ);
02663 return ary;
02664 }
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675 static VALUE
02676 env_each_value(VALUE ehash)
02677 {
02678 VALUE values;
02679 long i;
02680
02681 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02682 values = env_values();
02683 for (i=0; i<RARRAY_LEN(values); i++) {
02684 rb_yield(RARRAY_PTR(values)[i]);
02685 }
02686 return ehash;
02687 }
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700 static VALUE
02701 env_each_pair(VALUE ehash)
02702 {
02703 char **env;
02704 VALUE ary;
02705 long i;
02706
02707 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02708
02709 rb_secure(4);
02710 ary = rb_ary_new();
02711 env = GET_ENVIRON(environ);
02712 while (*env) {
02713 char *s = strchr(*env, '=');
02714 if (s) {
02715 rb_ary_push(ary, env_str_new(*env, s-*env));
02716 rb_ary_push(ary, env_str_new2(s+1));
02717 }
02718 env++;
02719 }
02720 FREE_ENVIRON(environ);
02721
02722 for (i=0; i<RARRAY_LEN(ary); i+=2) {
02723 rb_yield(rb_assoc_new(RARRAY_PTR(ary)[i], RARRAY_PTR(ary)[i+1]));
02724 }
02725 return ehash;
02726 }
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737 static VALUE
02738 env_reject_bang(VALUE ehash)
02739 {
02740 volatile VALUE keys;
02741 long i;
02742 int del = 0;
02743
02744 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02745 keys = env_keys();
02746 RBASIC(keys)->klass = 0;
02747 for (i=0; i<RARRAY_LEN(keys); i++) {
02748 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02749 if (!NIL_P(val)) {
02750 if (RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
02751 FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
02752 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02753 del++;
02754 }
02755 }
02756 }
02757 if (del == 0) return Qnil;
02758 return envtbl;
02759 }
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770 static VALUE
02771 env_delete_if(VALUE ehash)
02772 {
02773 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02774 env_reject_bang(ehash);
02775 return envtbl;
02776 }
02777
02778
02779
02780
02781
02782
02783
02784
02785 static VALUE
02786 env_values_at(int argc, VALUE *argv)
02787 {
02788 VALUE result;
02789 long i;
02790
02791 rb_secure(4);
02792 result = rb_ary_new();
02793 for (i=0; i<argc; i++) {
02794 rb_ary_push(result, rb_f_getenv(Qnil, argv[i]));
02795 }
02796 return result;
02797 }
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808 static VALUE
02809 env_select(VALUE ehash)
02810 {
02811 VALUE result;
02812 VALUE keys;
02813 long i;
02814
02815 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02816 rb_secure(4);
02817 result = rb_hash_new();
02818 keys = env_keys();
02819 for (i = 0; i < RARRAY_LEN(keys); ++i) {
02820 VALUE key = RARRAY_PTR(keys)[i];
02821 VALUE val = rb_f_getenv(Qnil, key);
02822 if (!NIL_P(val)) {
02823 if (RTEST(rb_yield_values(2, key, val))) {
02824 rb_hash_aset(result, key, val);
02825 }
02826 }
02827 }
02828
02829 return result;
02830 }
02831
02832
02833
02834
02835
02836
02837
02838
02839 static VALUE
02840 env_select_bang(VALUE ehash)
02841 {
02842 volatile VALUE keys;
02843 long i;
02844 int del = 0;
02845
02846 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02847 keys = env_keys();
02848 RBASIC(keys)->klass = 0;
02849 for (i=0; i<RARRAY_LEN(keys); i++) {
02850 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02851 if (!NIL_P(val)) {
02852 if (!RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
02853 FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
02854 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02855 del++;
02856 }
02857 }
02858 }
02859 if (del == 0) return Qnil;
02860 return envtbl;
02861 }
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872 static VALUE
02873 env_keep_if(VALUE ehash)
02874 {
02875 RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
02876 env_select_bang(ehash);
02877 return envtbl;
02878 }
02879
02880
02881
02882
02883
02884
02885
02886 VALUE
02887 rb_env_clear(void)
02888 {
02889 volatile VALUE keys;
02890 long i;
02891
02892 keys = env_keys();
02893 for (i=0; i<RARRAY_LEN(keys); i++) {
02894 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02895 if (!NIL_P(val)) {
02896 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02897 }
02898 }
02899 return envtbl;
02900 }
02901
02902
02903
02904
02905
02906
02907
02908 static VALUE
02909 env_to_s(void)
02910 {
02911 return rb_usascii_str_new2("ENV");
02912 }
02913
02914
02915
02916
02917
02918
02919
02920 static VALUE
02921 env_inspect(void)
02922 {
02923 char **env;
02924 VALUE str, i;
02925
02926 rb_secure(4);
02927 str = rb_str_buf_new2("{");
02928 env = GET_ENVIRON(environ);
02929 while (*env) {
02930 char *s = strchr(*env, '=');
02931
02932 if (env != environ) {
02933 rb_str_buf_cat2(str, ", ");
02934 }
02935 if (s) {
02936 rb_str_buf_cat2(str, "\"");
02937 rb_str_buf_cat(str, *env, s-*env);
02938 rb_str_buf_cat2(str, "\"=>");
02939 i = rb_inspect(rb_str_new2(s+1));
02940 rb_str_buf_append(str, i);
02941 }
02942 env++;
02943 }
02944 FREE_ENVIRON(environ);
02945 rb_str_buf_cat2(str, "}");
02946 OBJ_TAINT(str);
02947
02948 return str;
02949 }
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960 static VALUE
02961 env_to_a(void)
02962 {
02963 char **env;
02964 VALUE ary;
02965
02966 rb_secure(4);
02967 ary = rb_ary_new();
02968 env = GET_ENVIRON(environ);
02969 while (*env) {
02970 char *s = strchr(*env, '=');
02971 if (s) {
02972 rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
02973 env_str_new2(s+1)));
02974 }
02975 env++;
02976 }
02977 FREE_ENVIRON(environ);
02978 return ary;
02979 }
02980
02981
02982
02983
02984
02985
02986
02987
02988 static VALUE
02989 env_none(void)
02990 {
02991 return Qnil;
02992 }
02993
02994
02995
02996
02997
02998
02999
03000
03001 static VALUE
03002 env_size(void)
03003 {
03004 int i;
03005 char **env;
03006
03007 rb_secure(4);
03008 env = GET_ENVIRON(environ);
03009 for (i=0; env[i]; i++)
03010 ;
03011 FREE_ENVIRON(environ);
03012 return INT2FIX(i);
03013 }
03014
03015
03016
03017
03018
03019
03020
03021 static VALUE
03022 env_empty_p(void)
03023 {
03024 char **env;
03025
03026 rb_secure(4);
03027 env = GET_ENVIRON(environ);
03028 if (env[0] == 0) {
03029 FREE_ENVIRON(environ);
03030 return Qtrue;
03031 }
03032 FREE_ENVIRON(environ);
03033 return Qfalse;
03034 }
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045 static VALUE
03046 env_has_key(VALUE env, VALUE key)
03047 {
03048 char *s;
03049
03050 rb_secure(4);
03051 SafeStringValue(key);
03052 s = RSTRING_PTR(key);
03053 if (memchr(s, '\0', RSTRING_LEN(key)))
03054 rb_raise(rb_eArgError, "bad environment variable name");
03055 if (getenv(s)) return Qtrue;
03056 return Qfalse;
03057 }
03058
03059
03060
03061
03062
03063
03064
03065
03066 static VALUE
03067 env_assoc(VALUE env, VALUE key)
03068 {
03069 char *s, *e;
03070
03071 rb_secure(4);
03072 SafeStringValue(key);
03073 s = RSTRING_PTR(key);
03074 if (memchr(s, '\0', RSTRING_LEN(key)))
03075 rb_raise(rb_eArgError, "bad environment variable name");
03076 e = getenv(s);
03077 if (e) return rb_assoc_new(key, rb_tainted_str_new2(e));
03078 return Qnil;
03079 }
03080
03081
03082
03083
03084
03085
03086
03087
03088 static VALUE
03089 env_has_value(VALUE dmy, VALUE obj)
03090 {
03091 char **env;
03092
03093 rb_secure(4);
03094 obj = rb_check_string_type(obj);
03095 if (NIL_P(obj)) return Qnil;
03096 rb_check_safe_obj(obj);
03097 env = GET_ENVIRON(environ);
03098 while (*env) {
03099 char *s = strchr(*env, '=');
03100 if (s++) {
03101 long len = strlen(s);
03102 if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
03103 FREE_ENVIRON(environ);
03104 return Qtrue;
03105 }
03106 }
03107 env++;
03108 }
03109 FREE_ENVIRON(environ);
03110 return Qfalse;
03111 }
03112
03113
03114
03115
03116
03117
03118
03119
03120 static VALUE
03121 env_rassoc(VALUE dmy, VALUE obj)
03122 {
03123 char **env;
03124
03125 rb_secure(4);
03126 obj = rb_check_string_type(obj);
03127 if (NIL_P(obj)) return Qnil;
03128 rb_check_safe_obj(obj);
03129 env = GET_ENVIRON(environ);
03130 while (*env) {
03131 char *s = strchr(*env, '=');
03132 if (s++) {
03133 long len = strlen(s);
03134 if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
03135 VALUE result = rb_assoc_new(rb_tainted_str_new(*env, s-*env-1), obj);
03136 FREE_ENVIRON(environ);
03137 return result;
03138 }
03139 }
03140 env++;
03141 }
03142 FREE_ENVIRON(environ);
03143 return Qnil;
03144 }
03145
03146
03147
03148
03149
03150
03151
03152
03153 static VALUE
03154 env_key(VALUE dmy, VALUE value)
03155 {
03156 char **env;
03157 VALUE str;
03158
03159 rb_secure(4);
03160 SafeStringValue(value);
03161 env = GET_ENVIRON(environ);
03162 while (*env) {
03163 char *s = strchr(*env, '=');
03164 if (s++) {
03165 long len = strlen(s);
03166 if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
03167 str = env_str_new(*env, s-*env-1);
03168 FREE_ENVIRON(environ);
03169 return str;
03170 }
03171 }
03172 env++;
03173 }
03174 FREE_ENVIRON(environ);
03175 return Qnil;
03176 }
03177
03178
03179
03180
03181
03182
03183
03184 static VALUE
03185 env_index(VALUE dmy, VALUE value)
03186 {
03187 rb_warn("ENV.index is deprecated; use ENV.key");
03188 return env_key(dmy, value);
03189 }
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199 static VALUE
03200 env_to_hash(void)
03201 {
03202 char **env;
03203 VALUE hash;
03204
03205 rb_secure(4);
03206 hash = rb_hash_new();
03207 env = GET_ENVIRON(environ);
03208 while (*env) {
03209 char *s = strchr(*env, '=');
03210 if (s) {
03211 rb_hash_aset(hash, env_str_new(*env, s-*env),
03212 env_str_new2(s+1));
03213 }
03214 env++;
03215 }
03216 FREE_ENVIRON(environ);
03217 return hash;
03218 }
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228 static VALUE
03229 env_reject(void)
03230 {
03231 return rb_hash_delete_if(env_to_hash());
03232 }
03233
03234
03235
03236
03237
03238
03239
03240
03241 static VALUE
03242 env_shift(void)
03243 {
03244 char **env;
03245 VALUE result = Qnil;
03246
03247 rb_secure(4);
03248 env = GET_ENVIRON(environ);
03249 if (*env) {
03250 char *s = strchr(*env, '=');
03251 if (s) {
03252 VALUE key = env_str_new(*env, s-*env);
03253 VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
03254 env_delete(Qnil, key);
03255 result = rb_assoc_new(key, val);
03256 }
03257 }
03258 FREE_ENVIRON(environ);
03259 return result;
03260 }
03261
03262
03263
03264
03265
03266
03267
03268
03269 static VALUE
03270 env_invert(void)
03271 {
03272 return rb_hash_invert(env_to_hash());
03273 }
03274
03275 static int
03276 env_replace_i(VALUE key, VALUE val, VALUE keys)
03277 {
03278 env_aset(Qnil, key, val);
03279 if (rb_ary_includes(keys, key)) {
03280 rb_ary_delete(keys, key);
03281 }
03282 return ST_CONTINUE;
03283 }
03284
03285
03286
03287
03288
03289
03290
03291
03292 static VALUE
03293 env_replace(VALUE env, VALUE hash)
03294 {
03295 volatile VALUE keys;
03296 long i;
03297
03298 keys = env_keys();
03299 if (env == hash) return env;
03300 hash = to_hash(hash);
03301 rb_hash_foreach(hash, env_replace_i, keys);
03302
03303 for (i=0; i<RARRAY_LEN(keys); i++) {
03304 env_delete(env, RARRAY_PTR(keys)[i]);
03305 }
03306 return env;
03307 }
03308
03309 static int
03310 env_update_i(VALUE key, VALUE val)
03311 {
03312 if (rb_block_given_p()) {
03313 val = rb_yield_values(3, key, rb_f_getenv(Qnil, key), val);
03314 }
03315 env_aset(Qnil, key, val);
03316 return ST_CONTINUE;
03317 }
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329 static VALUE
03330 env_update(VALUE env, VALUE hash)
03331 {
03332 rb_secure(4);
03333 if (env == hash) return env;
03334 hash = to_hash(hash);
03335 rb_hash_foreach(hash, env_update_i, 0);
03336 return env;
03337 }
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426
03427
03428
03429
03430
03431
03432
03433
03434
03435
03436
03437
03438
03439
03440
03441
03442
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452 void
03453 Init_Hash(void)
03454 {
03455 #undef rb_intern
03456 #define rb_intern(str) rb_intern_const(str)
03457
03458 id_hash = rb_intern("hash");
03459 id_yield = rb_intern("yield");
03460 id_default = rb_intern("default");
03461
03462 rb_cHash = rb_define_class("Hash", rb_cObject);
03463
03464 rb_include_module(rb_cHash, rb_mEnumerable);
03465
03466 rb_define_alloc_func(rb_cHash, empty_hash_alloc);
03467 rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1);
03468 rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1);
03469 rb_define_method(rb_cHash,"initialize", rb_hash_initialize, -1);
03470 rb_define_method(rb_cHash,"initialize_copy", rb_hash_initialize_copy, 1);
03471 rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0);
03472
03473 rb_define_method(rb_cHash,"to_hash", rb_hash_to_hash, 0);
03474 rb_define_method(rb_cHash,"to_h", rb_hash_to_h, 0);
03475 rb_define_method(rb_cHash,"to_a", rb_hash_to_a, 0);
03476 rb_define_method(rb_cHash,"inspect", rb_hash_inspect, 0);
03477 rb_define_alias(rb_cHash, "to_s", "inspect");
03478
03479 rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
03480 rb_define_method(rb_cHash,"[]", rb_hash_aref, 1);
03481 rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
03482 rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
03483 rb_define_method(rb_cHash,"fetch", rb_hash_fetch_m, -1);
03484 rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
03485 rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
03486 rb_define_method(rb_cHash,"default", rb_hash_default, -1);
03487 rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1);
03488 rb_define_method(rb_cHash,"default_proc", rb_hash_default_proc, 0);
03489 rb_define_method(rb_cHash,"default_proc=", rb_hash_set_default_proc, 1);
03490 rb_define_method(rb_cHash,"key", rb_hash_key, 1);
03491 rb_define_method(rb_cHash,"index", rb_hash_index, 1);
03492 rb_define_method(rb_cHash,"size", rb_hash_size, 0);
03493 rb_define_method(rb_cHash,"length", rb_hash_size, 0);
03494 rb_define_method(rb_cHash,"empty?", rb_hash_empty_p, 0);
03495
03496 rb_define_method(rb_cHash,"each_value", rb_hash_each_value, 0);
03497 rb_define_method(rb_cHash,"each_key", rb_hash_each_key, 0);
03498 rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0);
03499 rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0);
03500
03501 rb_define_method(rb_cHash,"keys", rb_hash_keys, 0);
03502 rb_define_method(rb_cHash,"values", rb_hash_values, 0);
03503 rb_define_method(rb_cHash,"values_at", rb_hash_values_at, -1);
03504
03505 rb_define_method(rb_cHash,"shift", rb_hash_shift, 0);
03506 rb_define_method(rb_cHash,"delete", rb_hash_delete, 1);
03507 rb_define_method(rb_cHash,"delete_if", rb_hash_delete_if, 0);
03508 rb_define_method(rb_cHash,"keep_if", rb_hash_keep_if, 0);
03509 rb_define_method(rb_cHash,"select", rb_hash_select, 0);
03510 rb_define_method(rb_cHash,"select!", rb_hash_select_bang, 0);
03511 rb_define_method(rb_cHash,"reject", rb_hash_reject, 0);
03512 rb_define_method(rb_cHash,"reject!", rb_hash_reject_bang, 0);
03513 rb_define_method(rb_cHash,"clear", rb_hash_clear, 0);
03514 rb_define_method(rb_cHash,"invert", rb_hash_invert, 0);
03515 rb_define_method(rb_cHash,"update", rb_hash_update, 1);
03516 rb_define_method(rb_cHash,"replace", rb_hash_replace, 1);
03517 rb_define_method(rb_cHash,"merge!", rb_hash_update, 1);
03518 rb_define_method(rb_cHash,"merge", rb_hash_merge, 1);
03519 rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
03520 rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
03521 rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
03522
03523 rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1);
03524 rb_define_method(rb_cHash,"member?", rb_hash_has_key, 1);
03525 rb_define_method(rb_cHash,"has_key?", rb_hash_has_key, 1);
03526 rb_define_method(rb_cHash,"has_value?", rb_hash_has_value, 1);
03527 rb_define_method(rb_cHash,"key?", rb_hash_has_key, 1);
03528 rb_define_method(rb_cHash,"value?", rb_hash_has_value, 1);
03529
03530 rb_define_method(rb_cHash,"compare_by_identity", rb_hash_compare_by_id, 0);
03531 rb_define_method(rb_cHash,"compare_by_identity?", rb_hash_compare_by_id_p, 0);
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542 origenviron = environ;
03543 envtbl = rb_obj_alloc(rb_cObject);
03544 rb_extend_object(envtbl, rb_mEnumerable);
03545
03546 rb_define_singleton_method(envtbl,"[]", rb_f_getenv, 1);
03547 rb_define_singleton_method(envtbl,"fetch", env_fetch, -1);
03548 rb_define_singleton_method(envtbl,"[]=", env_aset, 2);
03549 rb_define_singleton_method(envtbl,"store", env_aset, 2);
03550 rb_define_singleton_method(envtbl,"each", env_each_pair, 0);
03551 rb_define_singleton_method(envtbl,"each_pair", env_each_pair, 0);
03552 rb_define_singleton_method(envtbl,"each_key", env_each_key, 0);
03553 rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
03554 rb_define_singleton_method(envtbl,"delete", env_delete_m, 1);
03555 rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
03556 rb_define_singleton_method(envtbl,"keep_if", env_keep_if, 0);
03557 rb_define_singleton_method(envtbl,"clear", rb_env_clear, 0);
03558 rb_define_singleton_method(envtbl,"reject", env_reject, 0);
03559 rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
03560 rb_define_singleton_method(envtbl,"select", env_select, 0);
03561 rb_define_singleton_method(envtbl,"select!", env_select_bang, 0);
03562 rb_define_singleton_method(envtbl,"shift", env_shift, 0);
03563 rb_define_singleton_method(envtbl,"invert", env_invert, 0);
03564 rb_define_singleton_method(envtbl,"replace", env_replace, 1);
03565 rb_define_singleton_method(envtbl,"update", env_update, 1);
03566 rb_define_singleton_method(envtbl,"inspect", env_inspect, 0);
03567 rb_define_singleton_method(envtbl,"rehash", env_none, 0);
03568 rb_define_singleton_method(envtbl,"to_a", env_to_a, 0);
03569 rb_define_singleton_method(envtbl,"to_s", env_to_s, 0);
03570 rb_define_singleton_method(envtbl,"key", env_key, 1);
03571 rb_define_singleton_method(envtbl,"index", env_index, 1);
03572 rb_define_singleton_method(envtbl,"size", env_size, 0);
03573 rb_define_singleton_method(envtbl,"length", env_size, 0);
03574 rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0);
03575 rb_define_singleton_method(envtbl,"keys", env_keys, 0);
03576 rb_define_singleton_method(envtbl,"values", env_values, 0);
03577 rb_define_singleton_method(envtbl,"values_at", env_values_at, -1);
03578 rb_define_singleton_method(envtbl,"include?", env_has_key, 1);
03579 rb_define_singleton_method(envtbl,"member?", env_has_key, 1);
03580 rb_define_singleton_method(envtbl,"has_key?", env_has_key, 1);
03581 rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1);
03582 rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
03583 rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
03584 rb_define_singleton_method(envtbl,"to_hash", env_to_hash, 0);
03585 rb_define_singleton_method(envtbl,"to_h", env_to_hash, 0);
03586 rb_define_singleton_method(envtbl,"assoc", env_assoc, 1);
03587 rb_define_singleton_method(envtbl,"rassoc", env_rassoc, 1);
03588
03589
03590
03591
03592
03593
03594 rb_define_global_const("ENV", envtbl);
03595 }
03596