From: "U.Nakamura" <usa@...>
Date: 2001-07-26T11:31:46+09:00
Subject: [ruby-dev:14097] DOSISH file.c

こんにちは、なかむら(う)@帰省中です。
最新のfile.cへのパッチです。
最新のfile.cからの差分に(たぶん)なっています。

1. \対応(オリジナルはCheng氏)
2. マルチバイト対応(1のため必須) 不完全かも...
3. ドライブ文字対応
4. [ruby-dev:14075]

File.joinへのパッチは含んでいませんが、必要ではあると思います。


--- current/file.c	Wed Jul 25 00:59:00 2001
+++ mytree/file.c	Thu Jul 26 11:00:08 2001
@@ -1300,4 +1300,5 @@ rb_file_s_umask(argc, argv)
 #define isdirsep(x) ((x) == '/')
 #endif
+
 #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
 # if defined(DJGPP)
@@ -1308,4 +1309,47 @@ rb_file_s_umask(argc, argv)
 #endif
 
+#ifdef DOSISH
+static inline int
+has_drive_letter(buf)
+    char *buf;
+{
+    if (ISALPHA(buf[0]) && buf[1] == ':') {
+	return 1;
+    }
+    else {
+	return 0;
+    }
+}
+
+static void
+getcwdofdrv(drv, buf, len)
+    int drv;
+    char *buf;
+    int len;
+{
+    char drive[4];
+    char oldcwd[MAXPATHLEN+1];
+
+    drive[0] = drv;
+    drive[1] = ':';
+    drive[2] = '\0';
+
+    /* the only way that I know to get the current directory
+       of a particular drive is to change chdir() to that drive,
+       so save the old cwd before chdir()
+    */
+    getcwd(oldcwd, MAXPATHLEN);
+    if (chdir(drive) == 0) {
+	getcwd(buf, len);
+	chdir(oldcwd);
+    }
+    else {
+	drive[2] = '/';
+	drive[3] = '\0';
+	strncpy(buf, drive, len);
+    }
+}
+#endif
+
 static char *
 strrdirsep(path)
@@ -1314,5 +1358,5 @@ strrdirsep(path)
     char *last = NULL;
 #ifdef DOSISH
-    if (ISALPHA(path[0]) && path[1] == ':') path += 2;
+    if (has_drive_letter(path)) path += 2;
 #endif
     while (*path) {
@@ -1327,4 +1371,10 @@ strrdirsep(path)
 }
 
+#if !defined(TOLOWER)
+#define TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c))
+#endif
+
+static int is_absolute_path _((const char*));
+
 VALUE
 rb_file_s_expand_path(argc, argv)
@@ -1333,5 +1383,5 @@ rb_file_s_expand_path(argc, argv)
 {
     VALUE fname, dname;
-    char *s, *p;
+    char *s, *p, *t;
     char buf[MAXPATHLEN+2];
     char *bend = buf + sizeof(buf) - 2;
@@ -1352,4 +1402,8 @@ rb_file_s_expand_path(argc, argv)
 	    if (strlen(dir) > MAXPATHLEN) goto toolong;
 	    strcpy(buf, dir);
+	    for (p = buf; *p && p < bend; p = CharNext(p)) {
+		if (isdirsep(*p)) *p = '/';
+	    }
+	    if (p >= bend) goto toolong;
 	    p = &buf[strlen(buf)];
 	    s++;
@@ -1362,5 +1416,7 @@ rb_file_s_expand_path(argc, argv)
 #endif
 	    while (*s && !isdirsep(*s)) {
-		*p++ = *s++;
+		for (t = CharNext(s); s != t; s++) {
+		    *p++ = *s;
+		}
 		if (p >= bend) goto toolong;
 	    }
@@ -1381,5 +1437,56 @@ rb_file_s_expand_path(argc, argv)
 #if defined DOSISH
     /* skip drive letter */
-    else if (ISALPHA(s[0]) && s[1] == ':' && isdirsep(s[2])) {
+    else if (has_drive_letter(s)) {
+	if (isdirsep(s[2])) {
+	    /* specified drive letter, and full path */
+	    /* skip drive letter */
+	    while (*s && !isdirsep(*s)) {
+		*p++ = *s++;
+		if (p >= bend) goto toolong;
+	    }
+	}
+	else {
+	    /* specified drive, but not full path */
+	    int same = 0;
+	    if (!NIL_P(dname)) {
+		dname = rb_file_s_expand_path(1, &dname);
+		if (has_drive_letter(RSTRING(dname)->ptr) &&
+		    TOLOWER(*RSTRING(dname)->ptr) == TOLOWER(s[0])) {
+		    /* ok, same drive */
+		    same = 1;
+		}
+	    }
+	    if (same) {
+		if (OBJ_TAINTED(dname)) tainted = 1;
+		if (strlen(RSTRING(dname)->ptr) > MAXPATHLEN) goto toolong;
+		strcpy(buf, RSTRING(dname)->ptr);
+		p = &buf[strlen(buf)];
+		s += 2;
+	    }
+	    else {
+		getcwdofdrv(*s, buf, MAXPATHLEN);
+		s += 2;
+
+		tainted = 1;
+		p = &buf[strlen(buf)];
+		if (*s) {
+		    /* need to append '/' before appending the rest of the path */
+		    if (!isdirsep(*(p - 1))) *p++ = '/';
+		    while (*s && !isdirsep(*s)) {
+			*p++ = *s++;
+			if (p >= bend) goto toolong;
+		    }
+		}
+	    }
+	}
+    }
+#endif
+#if defined DOSISH && ! defined(__CYGWIN__)
+    else if (isdirsep(*s) && !is_absolute_path(s)) {
+	/* specified full path, but not drive letter */
+	/* we need to get the drive letter */
+	tainted = 1;
+	getcwd(buf, MAXPATHLEN);
+	p = &buf[2];
 	while (*s && !isdirsep(*s)) {
 	    *p++ = *s++;
@@ -1388,5 +1495,5 @@ rb_file_s_expand_path(argc, argv)
     }
 #endif
-    else if (!isdirsep(*s)) {
+    else if (!is_absolute_path(s)) {
 	if (!NIL_P(dname)) {
 	    dname = rb_file_s_expand_path(1, &dname);
@@ -1400,5 +1507,5 @@ rb_file_s_expand_path(argc, argv)
 	}
 	p = &buf[strlen(buf)];
-	while (p > buf && *(p - 1) == '/') p--;
+	while (p > buf && strrdirsep(buf) == p - 1) p--;
     }
     else {
@@ -1415,5 +1522,8 @@ rb_file_s_expand_path(argc, argv)
 	switch (*s) {
 	  case '.':
-	    if (*(s+1)) {
+	    if (!isdirsep(*p)) {
+		*++p = '.';
+	    }
+	    else if (*(s+1)) {
 		switch (*++s) {
 		  case '.':
@@ -1425,9 +1535,6 @@ rb_file_s_expand_path(argc, argv)
 		    else {
 			*++p = '.';
-			do {
-			    *++p = '.';
-			    if (p >= bend) goto toolong;
-			} while (*++s == '.');
-			--s;
+			*++p = *s;
+			if (p >= bend) goto toolong;
 		    }
 		    break;
@@ -1436,5 +1543,6 @@ rb_file_s_expand_path(argc, argv)
 		  case '\\':
 #endif
-		    if (!isdirsep(*p)) *++p = '/';
+		    *(p + 1) = '\0';
+		    if (strrdirsep(buf) != p) *++p = '/';
 		    break;
 		  default:
@@ -1447,7 +1555,12 @@ rb_file_s_expand_path(argc, argv)
 	  case '\\':
 #endif
-	    if (!isdirsep(*p)) *++p = '/'; break;
+	    *(p + 1) = '\0';
+	    if (strrdirsep(buf) != p) *++p = '/';
+	    break;
 	  default:
-	    *++p = *s;
+	    for (t = CharNext(s); s != t; s++) {
+		*++p = *s;
+	    }
+	    s--;
 	    if (p >= bend) goto toolong;
 	}
@@ -1455,5 +1568,13 @@ rb_file_s_expand_path(argc, argv)
 
     /* Place a \0 at end. If path ends with a "/", delete it */
-    if (p == buf || !isdirsep(*p)) p++;
+    *(p + 1) = '\0';
+    if (p == buf || strrdirsep(buf) != p) p++;
+#if defined(DOSISH)
+    if (has_drive_letter(buf) && isdirsep(buf[2])) {
+	/* root directory needs a trailing backslash,
+	   otherwise it mean the current directory of the drive */
+	if (p == (buf+2)) p++;
+    }
+#endif
     *p = '\0';
 
@@ -1505,4 +1626,16 @@ rb_file_s_basename(argc, argv)
     p = strrdirsep(name);
     if (!p) {
+#if defined(DOSISH)
+	if (has_drive_letter(name)) {
+	    name += 2;
+	    if (NIL_P(fext)) {
+		f = strlen(name);
+	    }
+	    else {
+		f = rmext(name, ext);
+	   }
+	}
+	else
+#endif
 	if (NIL_P(fext) || !(f = rmext(name, ext)))
 	    return fname;
@@ -1532,8 +1665,19 @@ rb_file_s_dirname(klass, fname)
     p = strrdirsep(name);
     if (!p) {
+#if defined(DOSISH)
+	if (has_drive_letter(name)) {
+	    dirname = rb_str_new(name, 2);
+	    OBJ_INFECT(dirname, fname);
+	    return dirname;
+	}
+#endif
 	return rb_str_new2(".");
     }
     if (p == name)
 	p++;
+#if defined(DOSISH)
+    if (has_drive_letter(name) && p == &name[2])
+	p++;
+#endif
     dirname = rb_str_new(name, p - name);
     if (OBJ_TAINTED(fname)) OBJ_TAINT(dirname);
@@ -2164,5 +2308,5 @@ is_absolute_path(path)
 {
 #ifdef DOSISH
-    if (ISALPHA(path[0]) && path[1] == ':' && isdirsep(path[2])) return 1;
+    if (has_drive_letter(path) && isdirsep(path[2])) return 1;
     if (isdirsep(path[0]) && isdirsep(path[1])) return 1;
 #else

それでは
--
U.Nakamura <usa@osb.att.ne.jp>