18 |
18 |
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
|
19 |
19 |
#endif
|
20 |
20 |
|
|
21 |
static int sorted_loaded_features = 1;
|
21 |
22 |
|
22 |
23 |
static const char *const loadable_ext[] = {
|
23 |
24 |
".rb", DLEXT,
|
... | ... | |
129 |
130 |
return ST_STOP;
|
130 |
131 |
}
|
131 |
132 |
|
|
133 |
static int rb_feature_first_equal_or_greater(VALUE, const char *, long);
|
|
134 |
static int rb_stop_search_feature(VALUE, const char *, long);
|
|
135 |
|
132 |
136 |
static int
|
133 |
137 |
rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
|
134 |
138 |
{
|
... | ... | |
151 |
155 |
type = 0;
|
152 |
156 |
}
|
153 |
157 |
features = get_loaded_features();
|
154 |
|
for (i = 0; i < RARRAY_LEN(features); ++i) {
|
|
158 |
i = rb_feature_first_equal_or_greater(features, feature, len);
|
|
159 |
for (; i < RARRAY_LEN(features); ++i) {
|
155 |
160 |
v = RARRAY_PTR(features)[i];
|
|
161 |
if (rb_stop_search_feature(v, feature, len)) break;
|
156 |
162 |
f = StringValuePtr(v);
|
157 |
163 |
if ((n = RSTRING_LEN(v)) < len) continue;
|
158 |
164 |
if (strncmp(f, feature, len) != 0) {
|
... | ... | |
176 |
182 |
}
|
177 |
183 |
}
|
178 |
184 |
loading_tbl = get_loading_table();
|
179 |
|
if (loading_tbl) {
|
|
185 |
if (loading_tbl && loading_tbl->num_entries > 0) {
|
180 |
186 |
f = 0;
|
181 |
187 |
if (!expanded) {
|
182 |
188 |
struct loaded_feature_searching fs;
|
... | ... | |
251 |
257 |
return FALSE;
|
252 |
258 |
}
|
253 |
259 |
|
|
260 |
static int
|
|
261 |
feature_basename_length(const char *feature, long flen)
|
|
262 |
{
|
|
263 |
if (sorted_loaded_features) {
|
|
264 |
const char *ext = strrchr(feature, '.');
|
|
265 |
return ext && !strchr(ext, '/') ? ext - feature : flen;
|
|
266 |
} else {
|
|
267 |
return 0;
|
|
268 |
}
|
|
269 |
}
|
|
270 |
|
|
271 |
static int
|
|
272 |
compare_feature_name(const char *left, long llen, const char *right, long rlen)
|
|
273 |
{
|
|
274 |
int diff = 0;
|
|
275 |
while (llen-- && rlen--) {
|
|
276 |
diff = left[llen] - right[rlen];
|
|
277 |
if (diff) break;
|
|
278 |
if (left[llen] == '/') break;
|
|
279 |
}
|
|
280 |
return diff;
|
|
281 |
}
|
|
282 |
|
|
283 |
static int
|
|
284 |
rb_compare_feature_name(VALUE loaded, const char *feature, long flen)
|
|
285 |
{
|
|
286 |
const char *loaded_name = StringValuePtr(loaded);
|
|
287 |
long loaded_len = feature_basename_length(loaded_name, RSTRING_LEN(loaded));
|
|
288 |
return compare_feature_name(loaded_name, loaded_len, feature, flen);
|
|
289 |
}
|
|
290 |
|
|
291 |
/* used to find when equal features run out */
|
|
292 |
static int
|
|
293 |
rb_stop_search_feature(VALUE loaded, const char *feature, long flen)
|
|
294 |
{
|
|
295 |
if (sorted_loaded_features)
|
|
296 |
return rb_compare_feature_name(loaded, feature, flen) > 0;
|
|
297 |
else
|
|
298 |
return FALSE;
|
|
299 |
}
|
|
300 |
|
|
301 |
/* returns first position to search feature from */
|
|
302 |
static int
|
|
303 |
rb_feature_first_equal_or_greater(VALUE features, const char *feature, long flen)
|
|
304 |
{
|
|
305 |
if (sorted_loaded_features) {
|
|
306 |
int before = 0, first = RARRAY_LEN(features);
|
|
307 |
VALUE *values = RARRAY_PTR(features);
|
|
308 |
if (first == 0)
|
|
309 |
return 0;
|
|
310 |
if (rb_compare_feature_name(values[0], feature, flen) >= 0)
|
|
311 |
return 0;
|
|
312 |
|
|
313 |
while (first - before > 1) {
|
|
314 |
int mid = (first + before) / 2;
|
|
315 |
int cmp = rb_compare_feature_name(values[mid], feature, flen);
|
|
316 |
if (cmp >= 0)
|
|
317 |
first = mid;
|
|
318 |
else
|
|
319 |
before = mid;
|
|
320 |
}
|
|
321 |
return first;
|
|
322 |
} else {
|
|
323 |
return 0;
|
|
324 |
}
|
|
325 |
}
|
|
326 |
|
|
327 |
/* returns position to insert new feature in */
|
|
328 |
static int
|
|
329 |
rb_feature_first_greater(VALUE features, const char *feature, long flen)
|
|
330 |
{
|
|
331 |
if (sorted_loaded_features) {
|
|
332 |
int before = 0, first = RARRAY_LEN(features);
|
|
333 |
VALUE *values = RARRAY_PTR(features);
|
|
334 |
if (first == 0)
|
|
335 |
return 0;
|
|
336 |
if (rb_compare_feature_name(values[0], feature, flen) > 0)
|
|
337 |
return 0;
|
|
338 |
if (rb_compare_feature_name(values[first-1], feature, flen) <= 0)
|
|
339 |
return first;
|
|
340 |
|
|
341 |
while (first - before > 1) {
|
|
342 |
int mid = (first + before) / 2;
|
|
343 |
int cmp = rb_compare_feature_name(values[mid], feature, flen);
|
|
344 |
if (cmp > 0)
|
|
345 |
first = mid;
|
|
346 |
else
|
|
347 |
before = mid;
|
|
348 |
}
|
|
349 |
return first;
|
|
350 |
} else {
|
|
351 |
return RARRAY_LEN(features);
|
|
352 |
}
|
|
353 |
}
|
|
354 |
|
|
355 |
|
|
356 |
static VALUE
|
|
357 |
rb_push_feature_1(VALUE features, VALUE feature)
|
|
358 |
{
|
|
359 |
const char *fname = StringValuePtr(feature);
|
|
360 |
long flen = feature_basename_length(fname, RSTRING_LEN(feature));
|
|
361 |
int i = rb_feature_first_greater(features, fname, flen);
|
|
362 |
rb_ary_push(features, feature);
|
|
363 |
if ( i < RARRAY_LEN(features) - 1 ) {
|
|
364 |
MEMMOVE(RARRAY_PTR(features) + i + 1, RARRAY_PTR(features) + i,
|
|
365 |
VALUE, RARRAY_LEN(features) - i - 1);
|
|
366 |
RARRAY_PTR(features)[i] = feature;
|
|
367 |
}
|
|
368 |
return features;
|
|
369 |
}
|
|
370 |
|
|
371 |
static VALUE
|
|
372 |
rb_push_feature_m(int argc, VALUE *argv, VALUE features)
|
|
373 |
{
|
|
374 |
while (argc--) {
|
|
375 |
rb_push_feature_1(features, *argv++);
|
|
376 |
}
|
|
377 |
return features;
|
|
378 |
}
|
|
379 |
|
|
380 |
static VALUE
|
|
381 |
rb_concat_features(VALUE features, VALUE add)
|
|
382 |
{
|
|
383 |
add = rb_convert_type(add, T_ARRAY, "Array", "to_ary");
|
|
384 |
if (RARRAY_LEN(add)) {
|
|
385 |
rb_push_feature_m(RARRAY_LEN(add), RARRAY_PTR(add), features);
|
|
386 |
}
|
|
387 |
return features;
|
|
388 |
}
|
|
389 |
static const char *load_features_undefined_methods[] = {
|
|
390 |
"[]=", "reverse!", "rotate!", "sort!", "sort_by!",
|
|
391 |
"collect!", "map!", "shuffle!", "fill", "insert",
|
|
392 |
NULL
|
|
393 |
};
|
|
394 |
|
|
395 |
static VALUE
|
|
396 |
rb_loaded_features_init(void)
|
|
397 |
{
|
|
398 |
char *sorted_flag;
|
|
399 |
const char **name;
|
|
400 |
VALUE loaded_features = rb_ary_new();
|
|
401 |
VALUE loaded_features_c = rb_singleton_class(loaded_features);
|
|
402 |
|
|
403 |
sorted_flag = getenv("RUBY_LOADED_FEATURES_SORTED");
|
|
404 |
if (sorted_flag != NULL) {
|
|
405 |
int sorted_set = atoi(sorted_flag);
|
|
406 |
if (RTEST(ruby_verbose))
|
|
407 |
fprintf(stderr, "sorted_loaded_features=%d (%d)\n", sorted_set, sorted_loaded_features);
|
|
408 |
sorted_loaded_features = sorted_set;
|
|
409 |
}
|
|
410 |
|
|
411 |
for(name = load_features_undefined_methods; *name; name++) {
|
|
412 |
rb_undef_method(loaded_features_c, *name);
|
|
413 |
}
|
|
414 |
|
|
415 |
if (sorted_loaded_features) {
|
|
416 |
rb_define_method(loaded_features_c, "<<", rb_push_feature_1, 1);
|
|
417 |
rb_define_method(loaded_features_c, "push", rb_push_feature_m, -1);
|
|
418 |
rb_define_method(loaded_features_c, "concat", rb_concat_features, 1);
|
|
419 |
rb_define_method(loaded_features_c, "unshift", rb_push_feature_m, -1);
|
|
420 |
}
|
|
421 |
return loaded_features;
|
|
422 |
}
|
|
423 |
|
254 |
424 |
static void
|
255 |
425 |
rb_provide_feature(VALUE feature)
|
256 |
426 |
{
|
... | ... | |
258 |
428 |
rb_raise(rb_eRuntimeError,
|
259 |
429 |
"$LOADED_FEATURES is frozen; cannot append feature");
|
260 |
430 |
}
|
261 |
|
rb_ary_push(get_loaded_features(), feature);
|
|
431 |
rb_push_feature_1(get_loaded_features(), feature);
|
262 |
432 |
}
|
263 |
433 |
|
264 |
434 |
void
|
... | ... | |
788 |
958 |
|
789 |
959 |
rb_define_virtual_variable("$\"", get_loaded_features, 0);
|
790 |
960 |
rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
|
791 |
|
vm->loaded_features = rb_ary_new();
|
|
961 |
vm->loaded_features = rb_loaded_features_init();
|
792 |
962 |
|
793 |
963 |
rb_define_global_function("load", rb_f_load, -1);
|
794 |
964 |
rb_define_global_function("require", rb_f_require, 1);
|