Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 740 lines (662 sloc) 16.379 kB
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
1 /*
2 * MacRuby implementation of ENV.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
6 * Copyright (C) 2007-2010, Apple Inc. All rights reserved.
7 * Copyright (C) 1993-2007 Yukihiro Matsumoto
8 * Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
9 * Copyright (C) 2000 Information-technology Promotion Agency, Japan
10 */
11
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
12 #include "macruby_internal.h"
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
13 #include "ruby/st.h"
14 #include "ruby/util.h"
15 #include "ruby/node.h"
16 #include "vm.h"
17
59746d9 cleaning up a few things
Laurent Sansonetti authored
18 char ***_NSGetEnviron();
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
19
20 static VALUE envtbl;
21
22 static int path_tainted = -1;
23
24 static char **origenviron;
25 #define GET_ENVIRON() (*_NSGetEnviron())
26
27 static VALUE
28 to_hash(VALUE hash)
29 {
30 return rb_convert_type(hash, T_HASH, "Hash", "to_hash");
31 }
32
33 static VALUE
34 env_str_new(const char *ptr, long len)
35 {
36 VALUE str = rb_tainted_str_new(ptr, len);
37 rb_obj_freeze(str);
38 return str;
39 }
40
41 static VALUE
42 env_str_new2(const char *ptr)
43 {
44 if (ptr == NULL) {
45 return Qnil;
46 }
47 return env_str_new(ptr, strlen(ptr));
48 }
49
50 static VALUE
51 env_delete(VALUE obj, VALUE name)
52 {
53 rb_secure(4);
54 SafeStringValue(name);
55 const char *nam = RSTRING_PTR(name);
56 if (strlen(nam) != RSTRING_LEN(name)) {
57 rb_raise(rb_eArgError, "bad environment variable name");
58 }
59 const char *val = getenv(nam);
60 if (val != NULL) {
61 VALUE value = env_str_new2(val);
62 ruby_setenv(nam, 0);
63 if (strcmp(nam, PATH_ENV) == 0) {
64 path_tainted = 0;
65 }
66 return value;
67 }
68 return Qnil;
69 }
70
71 static VALUE
72 env_delete_m(VALUE obj, SEL sel, VALUE name)
73 {
74 VALUE val = env_delete(obj, name);
75 if (NIL_P(val) && rb_block_given_p()) {
76 rb_yield(name);
77 }
78 return val;
79 }
80
81 static VALUE
82 rb_f_getenv(VALUE obj, SEL sel, VALUE name)
83 {
84 rb_secure(4);
85 SafeStringValue(name);
86 const char *nam = RSTRING_PTR(name);
87 if (strlen(nam) != RSTRING_LEN(name)) {
88 rb_raise(rb_eArgError, "bad environment variable name");
89 }
90 const char *env = getenv(nam);
91 if (env != NULL) {
92 if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
93 VALUE str = rb_str_new2(env);
94 rb_obj_freeze(str);
95 return str;
96 }
97 return env_str_new2(env);
98 }
99 return Qnil;
100 }
101
102 static VALUE
103 env_fetch(VALUE rcv, SEL sel, int argc, VALUE *argv)
104 {
105 rb_secure(4);
106
107 VALUE key, if_none;
108 rb_scan_args(argc, argv, "11", &key, &if_none);
109
110 const bool block_given = rb_block_given_p();
111 if (block_given && argc == 2) {
112 rb_warn("block supersedes default value argument");
113 }
114 SafeStringValue(key);
115 const char *nam = RSTRING_PTR(key);
116 if (strlen(nam) != RSTRING_LEN(key)) {
117 rb_raise(rb_eArgError, "bad environment variable name");
118 }
119 const char *env = getenv(nam);
120 if (env == NULL) {
121 if (block_given) {
122 return rb_yield(key);
123 }
124 if (argc == 1) {
125 rb_raise(rb_eKeyError, "key not found");
126 }
127 return if_none;
128 }
129 if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
130 return rb_str_new2(env);
131 }
132 return env_str_new2(env);
133 }
134
135 static void
136 path_tainted_p(const char *path)
137 {
138 path_tainted = rb_path_check(path) ? 0 : 1;
139 }
140
141 int
142 rb_env_path_tainted(void)
143 {
144 if (path_tainted < 0) {
145 path_tainted_p(getenv(PATH_ENV));
146 }
147 return path_tainted;
148 }
149
150 void
151 ruby_setenv(const char *name, const char *value)
152 {
153 if (value != NULL) {
154 setenv(name, value, 1);
155 }
156 else {
157 unsetenv(name);
158 }
159 }
160
161 void
162 ruby_unsetenv(const char *name)
163 {
164 ruby_setenv(name, 0);
165 }
166
167 static VALUE
168 env_aset(VALUE obj, SEL sel, VALUE nm, VALUE val)
169 {
170 if (rb_safe_level() >= 4) {
171 rb_raise(rb_eSecurityError, "can't change environment variable");
172 }
173
174 if (NIL_P(val)) {
175 env_delete(obj, nm);
176 return Qnil;
177 }
178 StringValue(nm);
179 StringValue(val);
180 const char *name = RSTRING_PTR(nm);
181 const char *value = RSTRING_PTR(val);
182 if (strlen(name) != RSTRING_LEN(nm)) {
183 rb_raise(rb_eArgError, "bad environment variable name");
184 }
185 if (strlen(value) != RSTRING_LEN(val)) {
186 rb_raise(rb_eArgError, "bad environment variable value");
187 }
188
189 ruby_setenv(name, value);
190 if (strcmp(name, PATH_ENV) == 0) {
191 if (OBJ_TAINTED(val)) {
192 /* already tainted, no check */
193 path_tainted = 1;
194 return val;
195 }
196 else {
197 path_tainted_p(value);
198 }
199 }
200 return val;
201 }
202
203 static VALUE
204 env_keys(VALUE rcv, SEL sel)
205 {
206 rb_secure(4);
207
208 VALUE ary = rb_ary_new();
209 char **env = GET_ENVIRON();
210 while (*env != NULL) {
211 const char *s = strchr(*env, '=');
212 if (s != NULL) {
213 rb_ary_push(ary, env_str_new(*env, s - *env));
214 }
215 env++;
216 }
217 return ary;
218 }
219
220 static VALUE
221 env_each_key(VALUE ehash, SEL sel)
222 {
223 RETURN_ENUMERATOR(ehash, 0, 0);
224 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
225 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
226 rb_yield(RARRAY_AT(keys, i));
227 RETURN_IF_BROKEN();
228 }
229 return ehash;
230 }
231
232 static VALUE
233 env_values(VALUE rcv, SEL sel)
234 {
235 rb_secure(4);
236
237 VALUE ary = rb_ary_new();
238 char **env = GET_ENVIRON();
239 while (*env != NULL) {
240 const char *s = strchr(*env, '=');
241 if (s != NULL) {
242 rb_ary_push(ary, env_str_new2(s + 1));
243 }
244 env++;
245 }
246 return ary;
247 }
248
249 static VALUE
250 env_each_value(VALUE ehash, SEL sel)
251 {
252 RETURN_ENUMERATOR(ehash, 0, 0);
253 VALUE values = env_values(Qnil, 0); /* rb_secure(4); */
254 for (long i = 0, count = RARRAY_LEN(values); i < count; i++) {
255 rb_yield(RARRAY_AT(values, i));
256 RETURN_IF_BROKEN();
257 }
258 return ehash;
259 }
260
261 static VALUE
262 env_each_pair(VALUE ehash, SEL sel)
263 {
264 RETURN_ENUMERATOR(ehash, 0, 0);
265
266 rb_secure(4);
267 VALUE ary = rb_ary_new();
268 char **env = GET_ENVIRON();
269 while (*env != NULL) {
270 const char *s = strchr(*env, '=');
271 if (s != NULL) {
272 rb_ary_push(ary, env_str_new(*env, s - *env));
273 rb_ary_push(ary, env_str_new2(s + 1));
274 }
275 env++;
276 }
277
278 for (long i = 0, count = RARRAY_LEN(ary); i < count; i += 2) {
279 rb_yield(rb_assoc_new(RARRAY_AT(ary, i), RARRAY_AT(ary, i + 1)));
280 RETURN_IF_BROKEN();
281 }
282 return ehash;
283 }
284
285 static VALUE
286 env_reject_bang(VALUE ehash, SEL sel)
287 {
288 RETURN_ENUMERATOR(ehash, 0, 0);
289 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
290 bool deleted = false;
291 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
292 VALUE key = RARRAY_AT(keys, i);
293 VALUE val = rb_f_getenv(Qnil, 0, key);
294 if (!NIL_P(val)) {
295 VALUE v = rb_yield_values(2, key, val);
296 RETURN_IF_BROKEN();
297 if (RTEST(v)) {
298 rb_obj_untaint(key);
299 env_delete(Qnil, key);
300 deleted = true;
301 }
302 }
303 }
304 return deleted ? envtbl : Qnil;
305 }
306
307 static VALUE
308 env_delete_if(VALUE ehash, SEL sel)
309 {
310 RETURN_ENUMERATOR(ehash, 0, 0);
311 env_reject_bang(ehash, 0);
312 return envtbl;
313 }
314
315 static VALUE
316 env_values_at(VALUE rcv, SEL sel, int argc, VALUE *argv)
317 {
318 rb_secure(4);
319 VALUE result = rb_ary_new();
320 for (long i = 0; i < argc; i++) {
321 rb_ary_push(result, rb_f_getenv(Qnil, 0, argv[i]));
322 }
323 return result;
324 }
325
326 static VALUE
327 env_select(VALUE ehash, SEL sel)
328 {
329 RETURN_ENUMERATOR(ehash, 0, 0);
330 rb_secure(4);
331 VALUE result = rb_hash_new();
332 char **env = GET_ENVIRON();
333 while (*env != NULL) {
334 const char *s = strchr(*env, '=');
335 if (s != NULL) {
336 VALUE k = env_str_new(*env, s - *env);
337 VALUE v = env_str_new2(s + 1);
338 VALUE v2 = rb_yield_values(2, k, v);
339 RETURN_IF_BROKEN();
340 if (RTEST(v2)) {
341 rb_hash_aset(result, k, v);
342 }
343 }
344 env++;
345 }
346 return result;
347 }
348
349 static VALUE
350 rb_env_clear_imp(VALUE rcv, SEL sel)
351 {
352 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
353 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
354 VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
355 if (!NIL_P(val)) {
356 env_delete(Qnil, RARRAY_AT(keys, i));
357 }
358 }
359 return envtbl;
360 }
361
362 VALUE
363 rb_env_clear(void)
364 {
365 return rb_env_clear_imp(Qnil, 0);
366 }
367
368 static VALUE
369 env_to_s(VALUE rcv, SEL sel)
370 {
371 return rb_usascii_str_new2("ENV");
372 }
373
374 static VALUE
375 env_inspect(VALUE rcv, SEL sel)
376 {
377 rb_secure(4);
378
379 VALUE str = rb_str_buf_new2("{");
380 char **env = GET_ENVIRON();
381 while (*env != NULL) {
382 const char *s = strchr(*env, '=');
383
384 if (env != GET_ENVIRON()) {
385 rb_str_buf_cat2(str, ", ");
386 }
387 if (s != NULL) {
388 rb_str_buf_cat2(str, "\"");
389 rb_str_buf_cat(str, *env, s - *env);
390 rb_str_buf_cat2(str, "\"=>");
391 VALUE i = rb_inspect(rb_str_new2(s + 1));
392 rb_str_buf_append(str, i);
393 }
394 env++;
395 }
396 rb_str_buf_cat2(str, "}");
397 OBJ_TAINT(str);
398
399 return str;
400 }
401
402 static VALUE
403 env_to_a(VALUE rcv, SEL sel)
404 {
405 rb_secure(4);
406
407 VALUE ary = rb_ary_new();
408 char **env = GET_ENVIRON();
409 while (*env != NULL) {
410 const char *s = strchr(*env, '=');
411 if (s != NULL) {
412 rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s - *env),
413 env_str_new2(s + 1)));
414 }
415 env++;
416 }
417 return ary;
418 }
419
420 static VALUE
421 env_none(VALUE rcv, SEL sel)
422 {
423 return Qnil;
424 }
425
426 static VALUE
427 env_size(VALUE rcv, SEL sel)
428 {
429 rb_secure(4);
430
431 char **env = GET_ENVIRON();
432 int i = 0;
433 while (env[i] != NULL) {
434 i++;
435 }
436 return INT2FIX(i);
437 }
438
439 static VALUE
440 env_empty_p(VALUE rcv, SEL sel)
441 {
442 rb_secure(4);
443
444 char **env = GET_ENVIRON();
445 if (env[0] == NULL) {
446 return Qtrue;
447 }
448 return Qfalse;
449 }
450
451 static VALUE
452 env_has_key(VALUE env, SEL sel, VALUE key)
453 {
454 rb_secure(4);
455
456 const char *s = StringValuePtr(key);
457 if (strlen(s) != RSTRING_LEN(key)) {
458 rb_raise(rb_eArgError, "bad environment variable name");
459 }
460 if (getenv(s) != NULL) {
461 return Qtrue;
462 }
463 return Qfalse;
464 }
465
466 static VALUE
467 env_assoc(VALUE env, SEL sel, VALUE key)
468 {
469 rb_secure(4);
470
471 const char *s = StringValuePtr(key);
472 if (strlen(s) != RSTRING_LEN(key)) {
473 rb_raise(rb_eArgError, "bad environment variable name");
474 }
475 const char *e = getenv(s);
476 if (e != NULL) {
477 return rb_assoc_new(key, rb_tainted_str_new2(e));
478 }
479 return Qnil;
480 }
481
482 static VALUE
483 env_has_value(VALUE dmy, SEL sel, VALUE obj)
484 {
485 rb_secure(4);
486
487 obj = rb_check_string_type(obj);
488 if (NIL_P(obj)) {
489 return Qnil;
490 }
491 char **env = GET_ENVIRON();
492 while (*env != NULL) {
493 const char *s = strchr(*env, '=');
494 if (s++ != NULL) {
495 const long len = strlen(s);
496 if (RSTRING_LEN(obj) == len
497 && strncmp(s, RSTRING_PTR(obj), len) == 0) {
498 return Qtrue;
499 }
500 }
501 env++;
502 }
503 return Qfalse;
504 }
505
506 static VALUE
13f1b83 Add selector to the implementation of `ENV#rassoc`
Thibault Martin-Lagardette authored
507 env_rassoc(VALUE dmy, SEL sel, VALUE obj)
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
508 {
509 rb_secure(4);
510
511 obj = rb_check_string_type(obj);
512 if (NIL_P(obj)) {
513 return Qnil;
514 }
515 char **env = GET_ENVIRON();
516 while (*env != NULL) {
517 const char *s = strchr(*env, '=');
518 if (s++ != NULL) {
519 const long len = strlen(s);
520 if (RSTRING_LEN(obj) == len
521 && strncmp(s, RSTRING_PTR(obj), len) == 0) {
522 return rb_assoc_new(rb_tainted_str_new(*env, s - *env - 1),
523 obj);
524 }
525 }
526 env++;
527 }
528 return Qnil;
529 }
530
531 static VALUE
532 env_key(VALUE dmy, SEL sel, VALUE value)
533 {
534 rb_secure(4);
535
536 StringValue(value);
537 char **env = GET_ENVIRON();
538 while (*env != NULL) {
539 const char *s = strchr(*env, '=');
540 if (s++ != NULL) {
541 const long len = strlen(s);
542 if (RSTRING_LEN(value) == len
543 && strncmp(s, RSTRING_PTR(value), len) == 0) {
544 return env_str_new(*env, s - *env - 1);
545 }
546 }
547 env++;
548 }
549 return Qnil;
550 }
551
552 static VALUE
553 env_index(VALUE dmy, SEL sel, VALUE value)
554 {
555 rb_warn("ENV.index is deprecated; use ENV.key");
556 return env_key(dmy, 0, value);
557 }
558
559 static VALUE
560 env_to_hash(VALUE rcv, SEL sel)
561 {
562 rb_secure(4);
563
564 VALUE hash = rb_hash_new();
565 char **env = GET_ENVIRON();
566 while (*env != NULL) {
567 const char *s = strchr(*env, '=');
568 if (s != NULL) {
569 rb_hash_aset(hash, env_str_new(*env, s - *env),
570 env_str_new2(s + 1));
571 }
572 env++;
573 }
574 return hash;
575 }
576
577 static VALUE
578 env_reject(VALUE rcv, SEL sel)
579 {
580 rb_secure(4);
581
582 RETURN_ENUMERATOR(rcv, 0, 0);
583
584 VALUE hash = rb_hash_new();
585 char **env = GET_ENVIRON();
586 while (*env != NULL) {
587 const char *s = strchr(*env, '=');
588 if (s != NULL) {
589 VALUE key = env_str_new(*env, s - *env);
590 VALUE val = env_str_new2(s + 1);
591 if (!RTEST(rb_yield_values(2, key, val))) {
592 rb_hash_aset(hash, key, val);
593 }
594 }
595 env++;
596 }
597 return hash;
598 }
599
600 static VALUE
601 env_shift(VALUE rcv, SEL sel)
602 {
603 rb_secure(4);
604
605 char **env = GET_ENVIRON();
606 if (*env != NULL) {
607 const char *s = strchr(*env, '=');
608 if (s != NULL) {
609 VALUE key = env_str_new(*env, s - *env);
610 VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
611 env_delete(Qnil, key);
612 return rb_assoc_new(key, val);
613 }
614 }
615 return Qnil;
616 }
617
618 static VALUE
619 env_invert(VALUE rcv, SEL sel)
620 {
621 rb_secure(4);
622
623 VALUE hash = rb_hash_new();
624 char **env = GET_ENVIRON();
625 while (*env != NULL) {
626 const char *s = strchr(*env, '=');
627 if (s != NULL) {
628 rb_hash_aset(hash, env_str_new2(s + 1),
629 env_str_new(*env, s - *env));
630 }
631 env++;
632 }
633 return hash;
634 }
635
636 static int
637 env_replace_i(VALUE key, VALUE val, VALUE keys)
638 {
639 if (key != Qundef) {
640 env_aset(Qnil, 0, key, val);
641 if (rb_ary_includes(keys, key)) {
642 rb_ary_delete(keys, key);
643 }
644 }
645 return ST_CONTINUE;
646 }
647
648 static VALUE
649 env_replace(VALUE env, SEL sel, VALUE hash)
650 {
651 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
652 if (env == hash) {
653 return env;
654 }
655 hash = to_hash(hash);
656 rb_hash_foreach(hash, env_replace_i, keys);
657
658 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
659 env_delete(env, RARRAY_AT(keys, i));
660 }
661 return env;
662 }
663
664 static int
665 env_update_i(VALUE key, VALUE val)
666 {
667 if (key != Qundef) {
668 if (rb_block_given_p()) {
669 val = rb_yield_values(3, key, rb_f_getenv(Qnil, 0, key), val);
670 RETURN_IF_BROKEN();
671 }
672 env_aset(Qnil, 0, key, val);
673 }
674 return ST_CONTINUE;
675 }
676
677 static VALUE
678 env_update(VALUE env, SEL sel, VALUE hash)
679 {
680 rb_secure(4);
681 if (env == hash) {
682 return env;
683 }
684 hash = to_hash(hash);
685 rb_hash_foreach(hash, env_update_i, 0);
686 return env;
687 }
688
689 void
690 Init_ENV(void)
691 {
692 origenviron = GET_ENVIRON();
693 envtbl = rb_obj_alloc(rb_cObject);
694 rb_extend_object(envtbl, rb_mEnumerable);
695
696 VALUE klass = rb_singleton_class(envtbl);
697
698 rb_objc_define_method(klass, "[]", rb_f_getenv, 1);
699 rb_objc_define_method(klass, "fetch", env_fetch, -1);
700 rb_objc_define_method(klass, "[]=", env_aset, 2);
701 rb_objc_define_method(klass, "store", env_aset, 2);
702 rb_objc_define_method(klass, "each", env_each_pair, 0);
703 rb_objc_define_method(klass, "each_pair", env_each_pair, 0);
704 rb_objc_define_method(klass, "each_key", env_each_key, 0);
705 rb_objc_define_method(klass, "each_value", env_each_value, 0);
706 rb_objc_define_method(klass, "delete", env_delete_m, 1);
707 rb_objc_define_method(klass, "delete_if", env_delete_if, 0);
708 rb_objc_define_method(klass, "clear", rb_env_clear_imp, 0);
709 rb_objc_define_method(klass, "reject", env_reject, 0);
710 rb_objc_define_method(klass, "reject!", env_reject_bang, 0);
711 rb_objc_define_method(klass, "select", env_select, 0);
712 rb_objc_define_method(klass, "shift", env_shift, 0);
713 rb_objc_define_method(klass, "invert", env_invert, 0);
714 rb_objc_define_method(klass, "replace", env_replace, 1);
715 rb_objc_define_method(klass, "update", env_update, 1);
716 rb_objc_define_method(klass, "inspect", env_inspect, 0);
717 rb_objc_define_method(klass, "rehash", env_none, 0);
718 rb_objc_define_method(klass, "to_a", env_to_a, 0);
719 rb_objc_define_method(klass, "to_s", env_to_s, 0);
720 rb_objc_define_method(klass, "key", env_key, 1);
721 rb_objc_define_method(klass, "index", env_index, 1);
722 rb_objc_define_method(klass, "size", env_size, 0);
723 rb_objc_define_method(klass, "length", env_size, 0);
724 rb_objc_define_method(klass, "empty?", env_empty_p, 0);
725 rb_objc_define_method(klass, "keys", env_keys, 0);
726 rb_objc_define_method(klass, "values", env_values, 0);
727 rb_objc_define_method(klass, "values_at", env_values_at, -1);
728 rb_objc_define_method(klass, "include?", env_has_key, 1);
729 rb_objc_define_method(klass, "member?", env_has_key, 1);
730 rb_objc_define_method(klass, "has_key?", env_has_key, 1);
731 rb_objc_define_method(klass, "has_value?", env_has_value, 1);
732 rb_objc_define_method(klass, "key?", env_has_key, 1);
733 rb_objc_define_method(klass, "value?", env_has_value, 1);
734 rb_objc_define_method(klass, "to_hash", env_to_hash, 0);
735 rb_objc_define_method(klass, "assoc", env_assoc, 1);
736 rb_objc_define_method(klass, "rassoc", env_rassoc, 1);
737
738 rb_define_global_const("ENV", envtbl);
739 }
Something went wrong with that request. Please try again.