< :前の番号
^ :番号順リスト
> :次の番号
P :前の記事(自分と同じ返事先を持つ)
N :次の記事
|<:スレッドの先頭
>|:次のスレッド
^ :返事先
_:自分への返事
>:同じ返事先を持つ記事(前)
<:同じ返事先を持つ記事(後)
---:分割してスレッド表示、再表示
| :分割して(縦)スレッド表示、再表示
~ :スレッドのフレーム消去
.:インデックス
..:インデックスのインデックス
山本です。
[ruby-dev:22303]での
|>これだと、readdir(a)を?magicの時と(child)の列挙のとき2度
|>行っているので、これを1度にできないか考えています。
|と書きましたが、recursiveなほうはlstat()で、そうでないほうはstat()なので、
|単純にまとめるわけにはいきませんでした。
を実装してみました。かなりいじったのでバグの可能性が高まってますが、
自分でテストした限りでは動いているようなのでパッチを送ります。
まずいところがありましたら、指摘してください。
パターンによっては、倍近く高速化しました。
# g: 4787files, 166dirs
# ruby -Ks -e "Dir.glob('g:/**/*'){}"
0:08.458 # [ruby-dev:22431]
0:07.850 # this patch
# ruby -Ks -e "Dir.glob('g:/**/*/'){}"
0:15.303 # [ruby-dev:22431]
0:07.722 # this patch
--- dir.c-22431 Sat Dec 27 23:35:54 2003
+++ dir.c Sat Dec 27 23:30:54 2003
@@ -892,3 +892,3 @@ remove_backslashes(p, pend)
static int
-fnmatch_for_substr(p, pend, string, flags)
+do_fnmatch(p, pend, string, flags)
char *p;
@@ -908,2 +908,34 @@ fnmatch_for_substr(p, pend, string, flag
+static int
+do_stat(path, pst)
+ const char *path;
+ struct stat *pst;
+{
+ int ret = stat(path, pst);
+ if (ret < 0 && errno != ENOENT)
+ rb_sys_warning(path);
+ return ret;
+}
+
+static int
+do_lstat(path, pst)
+ const char *path;
+ struct stat *pst;
+{
+ int ret = lstat(path, pst);
+ if (ret < 0 && errno != ENOENT)
+ rb_sys_warning(path);
+ return ret;
+}
+
+static DIR *
+do_opendir(path)
+ const char *path;
+{
+ DIR *dirp = opendir(path);
+ if (dirp == NULL && errno != ENOENT && errno != ENOTDIR)
+ rb_sys_warning(path);
+ return dirp;
+}
+
#ifndef S_ISDIR
@@ -912,2 +944,10 @@ fnmatch_for_substr(p, pend, string, flag
+#ifndef S_ISLNK
+# ifndef S_IFLNK
+# define S_ISLNK(m) (0)
+# else
+# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+# endif
+#endif
+
struct glob_args {
@@ -961,5 +1001,6 @@ glob_helper(path, sub, separator, flags,
int recursive = 0;
+ int magical = 1;
struct d_link {
- char *path;
+ char *name;
struct d_link *next;
@@ -985,25 +1026,14 @@ glob_helper(path, sub, separator, flags,
if (*p == '\0') { /* magic not found */
- if (!separator) {
- if (lstat(path, &st) < 0) {
- /* In case stat error is other than ENOENT and
- we may want to know what is wrong. */
- if (errno != ENOENT) rb_sys_warning(path);
- }
- else {
- status = glob_call_func(func, path, arg);
- }
- }
- else {
- const char c = p[-1];
- p[-1] = '\0';
- if (lstat(path, &st) < 0) {
- if (errno != ENOENT) rb_sys_warning(path);
+ if (separator) {
+ char c = p[-1]; p[-1] = '\0';
+ if (do_lstat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
p[-1] = c;
+ return glob_call_func(func, path, arg);
}
- else if (S_ISDIR(st.st_mode)) {
- p[-1] = c;
- status = glob_call_func(func, path, arg);
}
+ else {
+ if (do_lstat(path, &st) == 0)
+ return glob_call_func(func, path, arg);
}
- return status;
+ return 0;
}
@@ -1011,73 +1041,60 @@ glob_helper(path, sub, separator, flags,
if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
- const int n = p - path;
recursive = 1;
- buf = ALLOC_N(char, n+strlen(p+3)+1);
- memcpy(buf, path, n);
- strcpy(buf+n, p+3);
- status = glob_helper(buf, buf+n, separator, flags, func, arg);
- free(buf);
+ memmove(p, p+3, strlen(p+3)+1); /* move '\0' too */
+ magical = has_magic(p, &m, flags); /* go to next element */
+ if (!magical) {
+ status = glob_helper(path, p, separator, flags, func, arg);
if (status) return status;
}
+ }
- {
- char *dir;
if (path == p) {
- dir = ALLOC_N(char, 2);
- dir[0] = '.';
- dir[1] = '\0';
+ dirp = do_opendir(".");
+ if (dirp == NULL) return 0;
}
else {
- const int n = separator ? (p - path) - 1 : (p - path);
- dir = ALLOC_N(char, n+1);
- memcpy(dir, path, n);
- dir[n] = '\0';
- }
- dirp = opendir(dir);
- if (dirp == NULL) {
- if (errno != ENOENT && errno != ENOTDIR) rb_sys_warning(dir);
- free(dir);
- return 0;
- }
- free(dir);
+ char *t = separator ? p-1 : p;
+ char c = *t; *t = '\0';
+ dirp = do_opendir(path);
+ *t = c;
+ if (dirp == NULL) return 0;
}
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ for (dp = readdir(dirp); dp != NULL && status == 0; dp = readdir(dirp)) {
+ int notdir = 0;
+ if (recursive && strcmp(".", dp->d_name) != 0 && strcmp("..", dp->d_name) != 0) {
const int n = p - path;
- if (recursive) {
- if (strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0)
- continue;
- buf = ALLOC_N(char, n+NAMLEN(dp)+strlen(m)+3+1);
+ buf = ALLOC_N(char, n+NAMLEN(dp)+1);
memcpy(buf, path, n);
strcpy(buf+n, dp->d_name);
- if (lstat(buf, &st) < 0) {
- if (errno != ENOENT) rb_sys_warning(buf);
- free(buf);
- continue;
- }
+ if (do_lstat(buf, &st) == 0)
if (S_ISDIR(st.st_mode)) {
- char *t = buf+strlen(buf);
- memcpy(t, "/**", 3);
- strcpy(t+3, m);
- status = glob_helper(buf, t+1, 1, flags, func, arg);
- free(buf);
- if (status) break;
- continue;
+ tmp = ALLOC(struct d_link);
+ tmp->name = ALLOC_N(char, NAMLEN(dp)+1);
+ strcpy(tmp->name, dp->d_name);
+ *tail = tmp;
+ tail = &tmp->next;
}
+ else if (!(S_ISLNK(st.st_mode) && do_stat(buf, &st) == 0 && S_ISDIR(st.st_mode)))
+ notdir = 1;
+ else
+ notdir = 1;
free(buf);
- continue;
}
- if (fnmatch_for_substr(p, m, dp->d_name, flags) == 0) {
- buf = ALLOC_N(char, n+NAMLEN(dp)+1);
- memcpy(buf, path, n);
- strcpy(buf+n, dp->d_name);
+ if (notdir && *m == '/')
+ continue;
+ if (magical && do_fnmatch(p, m, dp->d_name, flags) == 0) {
+ const int n1 = p - path;
+ const int n2 = NAMLEN(dp);
+ buf = ALLOC_N(char, n1+n2+strlen(m)+1);
+ memcpy(buf, path, n1);
+ strcpy(buf+n1, dp->d_name);
if (*m == '\0') {
status = glob_call_func(func, buf, arg);
- free(buf);
- if (status) break;
- continue;
}
- tmp = ALLOC(struct d_link);
- tmp->path = buf;
- *tail = tmp;
- tail = &tmp->next;
+ else {
+ strcpy(buf+n1+n2, m);
+ status = glob_helper(buf, buf+n1+n2+1, 1, flags, func, arg);
+ }
+ free(buf);
}
@@ -1088,19 +1105,15 @@ glob_helper(path, sub, separator, flags,
if (status == 0) {
- if (stat(link->path, &st) == 0) {
- if (S_ISDIR(st.st_mode)) {
- const int len = strlen(link->path);
- buf = ALLOC_N(char, len+strlen(m)+1);
- memcpy(buf, link->path, len);
- strcpy(buf+len, m);
- status = glob_helper(buf, buf+len+1, 1, flags, func, arg);
+ const int n1 = p - path;
+ const int n2 = strlen(link->name);
+ buf = ALLOC_N(char, n1+n2+4+strlen(p)+1);
+ memcpy(buf, path, n1);
+ strcpy(buf+n1, link->name);
+ strcpy(buf+n1+n2, "/**/");
+ strcpy(buf+n1+n2+4, p);
+ status = glob_helper(buf, buf+n1+n2+1, 1, flags, func, arg);
free(buf);
}
- }
- else {
- rb_sys_warning(link->path);
- }
- }
tmp = link;
link = link->next;
- free(tmp->path);
+ free(tmp->name);
free(tmp);