Skip to content

HTTPS clone URL

Subversion checkout URL

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