[#23168] File.fnmatch のリファクタリング — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

13 messages 2004/03/08

[#23192] File.fnmatch と Dir.glob の非互換部分 — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

19 messages 2004/03/13
[#23194] Re: File.fnmatch と Dir.glob の非互換部分 — matz@... (Yukihiro Matsumoto) 2004/03/13

まつもと ゆきひろです

[#23195] Re: File.fnmatch とDir.glob の非互換部分 — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2004/03/14

山本です。

[#23196] Re: File.fnmatch とDir.glob の非互換部分 — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2004/03/14

山本です。

[#23260] Re: File.fnmatch とDir.glob の非互換部分 — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2004/03/30

山本です。

[#23261] Re: File.fnmatch とDir.glob の非互換部分 — matz@... (Yukihiro Matsumoto) 2004/03/30

まつもと ゆきひろです

[#23265] Re: File.fnmatch とDir.glob の非互換部分 — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2004/03/30

山本です。

[#23238] Re: [ruby-cvs] ruby, ruby/lib, ruby/lib/rss, ruby/sample/openssl: * lib/logger.rb: trim tail space of each line. no user visible change. — Kouhei Sutou <kou@...>

須藤です.

10 messages 2004/03/27

[ruby-dev:23195] Re: File.fnmatch とDir.glob の非互換部分

From: "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>
Date: 2004-03-14 04:28:05 UTC
List: ruby-dev #23195
山本です。

>|今わかっている File.fnmatch と Dir.glob の非互換部分は以下のとおりです。
>|
>|1. '[' と ']' の間に '/' がある場合
>|2. '[' が閉じていない場合
>|3. '\/' という風に、'/' をエスケープしている場合
>|
>|1. は [ruby-dev:22873] でのまつもとさんの意見から File.fnmatch の 「'/' を無視する」で決定済みだと
>|思われますが、これを実装するには、2. もはっきりさせる必要があります。
>|
>|現在の動作は、File.fnmatch が「全ての文字にマッチしない」で、Dir.glob が「'[' を通常文字扱い」です。
>|rubyの正規表現ではエラーなので前者という考え方と、POSIX.2で後者という考え方があると思います。
>|どちらがいいでしょうか?
>|
>|領域指定で正規表現に合わせたので前者が自然だと思いますが、決まったほうで実装したいと思います。
>|実装していて気づいたことがあれば、その時報告します。
>
>どっちでもよいですが、とりあえず前者(マッチしない)でどうでしょ
>うか。やってみてまずければ変えればよいんだし。

前者で 1. 2. を実装してみたのですが、

E:\ruby-cvs>touch [
Touch  Version 4.2  Copyright (c) 1998 Borland International

E:\ruby-cvs>touch ]
Touch  Version 4.2  Copyright (c) 1998 Borland International

E:\ruby-cvs>ruby\miniruby.exe -e "puts Dir.glob('[')"

E:\ruby-cvs>ruby\miniruby.exe -e "puts Dir.glob(']')"
]

となってしまいました。閉じていない ']' も「全てにマッチしない」にするべきなのか、後者を選んで
両方通常文字扱いにすべきなのか・・・・それとも、これで問題ないのか。皆さんどう思われますか?

3. は意外と根が深そうなので、後回しにしています。(**\/ === **/ とすべきなのか?など、他の部分の
実装にも関係してくる)

パッチは下のとおりです。

cvs diff -u -wb -p dir.c (in directory E:\ruby-cvs\ruby\)
Index: dir.c
===================================================================
RCS file: /ruby/ruby/dir.c,v
retrieving revision 1.112
diff -u -w -b -p -r1.112 dir.c
--- dir.c	12 Mar 2004 15:00:39 -0000	1.112
+++ dir.c	14 Mar 2004 04:15:00 -0000
@@ -940,23 +940,52 @@ has_magic(s, flags)
      const char *s;
      int flags;
 {
+    const int escape = !(flags & FNM_NOESCAPE);
     register const char *p = s;
     register char c;
-    int open = 0;
-    int escape = !(flags & FNM_NOESCAPE);
 
     while (c = *p++) {
 	switch (c) {
+	  case '[':
 	  case '?':
 	  case '*':
 	    return 1;
 
-	  case '[':	/* Only accept an open brace if there is a close */
-	    open++;	/* brace to match it.  Bracket expressions must be */
-	    continue;	/* complete, according to Posix.2 */
+	  case '\\':
+	    if (escape && !(c = *p++))
+		return 0;
+	    continue;
+	}
+
+	p = Next(p-1);
+    }
+
+    return 0;
+}
+
+/* Find directory separator in pattern.  */
+static char *
+find_patsep(s, flags)
+    const char *s;
+    int flags;
+{
+    const int escape = !(flags & FNM_NOESCAPE);
+    register const char *p = s;
+    register char c;
+    int open = 0;
+
+    while (c = *p++) {
+	switch (c) {
+	  case '[':
+	    open = 1;
+	    continue;
 	  case ']':
-	    if (open)
-		return 1;
+	    open = 0;
+	    continue;
+
+	  case '/':
+	    if (!open)
+		return (char *)p-1;
 	    continue;
 
 	  case '\\':
@@ -968,7 +997,7 @@ has_magic(s, flags)
 	p = Next(p-1);
     }
 
-    return 0;
+    return (char *)p-1;
 }
 
 /* Remove escaping baskclashes */
@@ -1010,23 +1039,21 @@ glob_make_pattern(p, flags)
     const char *p;
     int flags;
 {
-    char *buf;
-    int dirsep = 0; /* pattern terminates with '/' */
     struct glob_pattern *list, *tmp, **tail = &list;
+    int dirsep = 0; /* pattern is terminated with '/' */
 
     while (*p) {
 	tmp = ALLOC(struct glob_pattern);
 	if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
-	    /* fold continuous RECURSIVEs */
+	    /* fold continuous RECURSIVEs (for glob_helper) */
 	    do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
 	    tmp->type = RECURSIVE;
 	    tmp->str = 0;
 	    dirsep = 1;
 	}
 	else {
-	    const char *m;
-	    for (m = p; *m && *m != '/'; Inc(m));
-	    buf = ALLOC_N(char, m-p+1);
+	    const char *m = find_patsep(p);
+	    char *buf = ALLOC_N(char, m-p+1);
 	    memcpy(buf, p, m-p);
 	    buf[m-p] = '\0';
 	    tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN;


In This Thread