Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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.