Project

General

Profile

Bug #13167 ยป 0001-dir.c-performance-fix-with-braces.patch

h.shirosaki (Hiroshi Shirosaki), 02/06/2018 02:09 AM

View differences:

dir.c
1527 1527
}
1528 1528

  
1529 1529
/* Globing pattern */
1530
enum glob_pattern_type { PLAIN, ALPHA, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
1530
enum glob_pattern_type { PLAIN, ALPHA, BRACE, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
1531 1531

  
1532 1532
/* Return nonzero if S has any special globbing chars in it.  */
1533 1533
static enum glob_pattern_type
......
1535 1535
{
1536 1536
    const int escape = !(flags & FNM_NOESCAPE);
1537 1537
    int hasalpha = 0;
1538
    int hasmagical = 0;
1538 1539

  
1539 1540
    register char c;
1540 1541

  
1541 1542
    while (p < pend && (c = *p++) != 0) {
1542 1543
	switch (c) {
1544
	  case '{':
1545
	    return BRACE;
1546

  
1543 1547
	  case '*':
1544 1548
	  case '?':
1545 1549
	  case '[':
1546
	    return MAGICAL;
1550
	    hasmagical = 1;
1551
	    break;
1547 1552

  
1548 1553
	  case '\\':
1549 1554
	    if (escape && p++ >= pend)
......
1568 1573
	p = Next(p-1, pend, enc);
1569 1574
    }
1570 1575

  
1571
    return hasalpha ? ALPHA : PLAIN;
1576
    return hasmagical ? MAGICAL : hasalpha ? ALPHA : PLAIN;
1572 1577
}
1573 1578

  
1574 1579
/* Find separator in globbing pattern. */
......
1589 1594
	    open = 0;
1590 1595
	    continue;
1591 1596

  
1597
	  case '{':
1598
	    open = 1;
1599
	    continue;
1600
	  case '}':
1601
	    open = 0;
1602
	    continue;
1603

  
1592 1604
	  case '/':
1593 1605
	    if (!open)
1594 1606
		return (char *)p-1;
......
1664 1676
	    const enum glob_pattern_type non_magic = (USE_NAME_ON_FS || FNM_SYSCASE) ? PLAIN : ALPHA;
1665 1677
	    char *buf;
1666 1678

  
1679
	    if (magic == BRACE) {
1680
		/* brace pattern is parsed after expansion */
1681
		buf = GLOB_ALLOC_N(char, e-p+1);
1682
		if (!buf) {
1683
		    GLOB_FREE(tmp);
1684
		    goto error;
1685
		}
1686
		memcpy(buf, p, e-p);
1687
		buf[e-p] = '\0';
1688
		tmp->type = BRACE;
1689
		tmp->str = buf;
1690
		*tail = tmp;
1691
		tmp->next = 0;
1692
		return list;
1693
	    }
1667 1694
	    if (!(FNM_SYSCASE || magic > non_magic) && !recursive && *m) {
1668 1695
		const char *m2;
1669 1696
		while (has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) <= non_magic &&
......
1994 2021
    return 0;
1995 2022
}
1996 2023

  
2024
struct push_glob_args {
2025
    int fd;
2026
    const char *path;
2027
    size_t baselen;
2028
    size_t namelen;
2029
    int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */
2030
    rb_pathtype_t pathtype; /* type of 'path' */
2031
    int flags;
2032
    const ruby_glob_funcs_t *funcs;
2033
    VALUE arg;
2034
};
2035

  
2036
struct dirent_brace_args {
2037
    const char *name;
2038
    const struct dirent *dp;
2039
    int flags;
2040
};
2041

  
2042
static int
2043
dirent_match_brace(const char *pattern, VALUE val, void *enc)
2044
{
2045
    struct dirent_brace_args *arg = (struct dirent_brace_args *)val;
2046

  
2047
    return dirent_match(pattern, enc, arg->name, arg->dp, arg->flags);
2048
}
2049

  
2050
/* join paths from pattern list of glob_make_pattern() */
2051
static const char*
2052
join_path_from_pattern(struct glob_pattern **beg)
2053
{
2054
    struct glob_pattern *p;
2055
    const char *path = "";
2056

  
2057
    for (p = *beg; p; p = p->next) {
2058
	const char *str;
2059
	switch (p->type) {
2060
	  case RECURSIVE:
2061
	    str = "**";
2062
	    break;
2063
	  default:
2064
	    str = p->str;
2065
	}
2066
	path = join_path(path, strlen(path), (p != *beg), str, strlen(str));
2067
    }
2068
    return path;
2069
}
2070

  
2071
static int push_caller(const char *path, VALUE val, void *enc);
2072

  
2073
static int ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
2074
			     rb_encoding *enc, VALUE var);
2075

  
1997 2076
static int
1998 2077
glob_helper(
1999 2078
    int fd,
......
2012 2091
    struct stat st;
2013 2092
    int status = 0;
2014 2093
    struct glob_pattern **cur, **new_beg, **new_end;
2015
    int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
2094
    int plain = 0, brace = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
2016 2095
    int escape = !(flags & FNM_NOESCAPE);
2017 2096
    size_t pathlen = baselen + namelen;
2018 2097
    const char *base = path;
......
2036 2115
	    magical = 1;
2037 2116
#endif
2038 2117
	    break;
2118
	  case BRACE:
2119
	    brace = 1;
2120
	    break;
2039 2121
	  case MAGICAL:
2040 2122
	    magical = 2;
2041 2123
	    break;
......
2050 2132
	}
2051 2133
    }
2052 2134

  
2135
    if (brace) {
2136
	struct push_glob_args args;
2137
	const char* brace_path = join_path_from_pattern(beg);
2138
	args.fd = fd;
2139
	args.path = path;
2140
	args.baselen = baselen;
2141
	args.namelen = namelen;
2142
	args.dirsep = dirsep;
2143
	args.flags = flags;
2144
	args.funcs = funcs;
2145
	args.arg = arg;
2146
	return ruby_brace_expand(brace_path, flags, push_caller, (VALUE)&args, enc, Qfalse);
2147
    }
2148

  
2053 2149
    if (*base) {
2054 2150
	if (match_all && pathtype == path_unknown) {
2055 2151
	    if (do_lstat(fd, base, &st, flags, enc) == 0) {
......
2186 2282

  
2187 2283
	    for (cur = beg; cur < end; ++cur) {
2188 2284
		struct glob_pattern *p = *cur;
2285
		struct dirent_brace_args args;
2189 2286
		if (p->type == RECURSIVE) {
2190 2287
		    if (new_pathtype == path_directory || /* not symlink but real directory */
2191 2288
			new_pathtype == path_exist) {
......
2195 2292
		    p = p->next; /* 0 times recursion */
2196 2293
		}
2197 2294
		switch (p->type) {
2295
		  case BRACE:
2296
		    args.name = name;
2297
		    args.dp = dp;
2298
		    args.flags = flags;
2299
		    if (ruby_brace_expand(p->str, flags, dirent_match_brace,
2300
					  (VALUE)&args, enc, Qfalse) > 0)
2301
			*new_end++ = p->next;
2302
		    break;
2198 2303
		  case ALPHA:
2199 2304
# if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2200 2305
		    if (plainname) {
......
2293 2398
}
2294 2399

  
2295 2400
static int
2401
push_caller(const char *path, VALUE val, void *enc)
2402
{
2403
    struct push_glob_args *arg = (struct push_glob_args *)val;
2404
    struct glob_pattern *list;
2405
    int status;
2406

  
2407
    list = glob_make_pattern(path, path + strlen(path), arg->flags, enc);
2408
    if (!list) {
2409
	return -1;
2410
    }
2411
    status = glob_helper(arg->fd, arg->path, arg->baselen, arg->namelen, arg->dirsep,
2412
			 arg->pathtype, &list, &list + 1, arg->flags, arg->funcs,
2413
			 arg->arg, enc);
2414
    glob_free_pattern(list);
2415
    return status;
2416
}
2417

  
2418
static int
2296 2419
ruby_glob0(const char *path, int fd, const char *base, int flags,
2297 2420
	   const ruby_glob_funcs_t *funcs, VALUE arg,
2298 2421
	   rb_encoding *enc)
......
2484 2607
    return ruby_brace_glob_with_enc(str, flags, func, arg, rb_ascii8bit_encoding());
2485 2608
}
2486 2609

  
2487
struct push_glob_args {
2488
    struct glob_args glob;
2489
    int flags;
2490
    int fd;
2491
};
2492

  
2493
static int
2494
push_caller(const char *path, VALUE val, void *enc)
2495
{
2496
    struct push_glob_args *arg = (struct push_glob_args *)val;
2497

  
2498
    return ruby_glob0(path, arg->fd, arg->glob.base, arg->flags, &rb_glob_funcs,
2499
		      (VALUE)&arg->glob, enc);
2500
}
2501

  
2502 2610
static int
2503 2611
push_glob(VALUE ary, VALUE str, VALUE base, int flags)
2504 2612
{
2505
    struct push_glob_args args;
2613
    struct glob_args args;
2614
    int fd;
2506 2615
    rb_encoding *enc = rb_enc_get(str);
2507 2616

  
2508 2617
#if defined _WIN32 || defined __APPLE__
......
2513 2622
    if (rb_enc_to_index(enc) == ENCINDEX_US_ASCII)
2514 2623
	enc = rb_ascii8bit_encoding();
2515 2624
    flags |= GLOB_VERBOSE;
2516
    args.glob.func = push_pattern;
2517
    args.glob.value = ary;
2518
    args.glob.enc = enc;
2519
    args.glob.base = 0;
2520
    args.flags = flags;
2521
    args.fd = AT_FDCWD;
2625
    args.func = push_pattern;
2626
    args.value = ary;
2627
    args.enc = enc;
2628
    args.base = 0;
2629
    fd = AT_FDCWD;
2522 2630
    if (!NIL_P(base)) {
2523 2631
	if (!RB_TYPE_P(base, T_STRING) || !rb_enc_check(str, base)) {
2524 2632
	    struct dir_data *dirp = DATA_PTR(base);
2525 2633
	    if (!dirp->dir) dir_closed();
2526 2634
#ifdef HAVE_DIRFD
2527
	    if ((args.fd = dirfd(dirp->dir)) == -1)
2635
	    if ((fd = dirfd(dirp->dir)) == -1)
2528 2636
		rb_sys_fail_path(dir_inspect(base));
2529 2637
#endif
2530 2638
	    base = dirp->path;
2531 2639
	}
2532
	args.glob.base = RSTRING_PTR(base);
2640
	args.base = RSTRING_PTR(base);
2533 2641
    }
2534 2642
#if defined _WIN32 || defined __APPLE__
2535 2643
    enc = rb_utf8_encoding();
2536 2644
#endif
2537 2645

  
2538
    return ruby_brace_expand(RSTRING_PTR(str), flags,
2539
			     push_caller, (VALUE)&args, enc, str);
2646
    return ruby_glob0(RSTRING_PTR(str), fd, args.base, flags, &rb_glob_funcs,
2647
		      (VALUE)&args, enc);
2540 2648
}
2541 2649

  
2542 2650
static VALUE
2543
-