From: nobu.nakada@... Date: 2000-05-28T03:05:26+09:00 Subject: [ruby-dev:9875] Re: $0 handling on NT なかだです。 At Fri, 26 May 2000 21:11:51 +0900, Katsuyuki Komatsu wrote: > | それと、Windows で(DOS では少なかったような気がする)日本語のファイル > |名をつける人って結構いるんですが、2byte 目に '\' を含むパス名ってどう > |したもんでしょうかねぇ。SJIS 決めうちってわけにはいかないし。 > > win32/win32.cでは、CharPrev()とCharNext()を使ってます。 CharNext() ってなに? とか思ったら Win32 API ですか。 > path++みたいなところを全部マクロか関数にしてWin32だったら > CharPrev()とCharNext()を使うというような形はどうですか? こんなでしょうか。ついでに basename, dirname でドライブ付きの 場合も手を加えてみました。 > |--- current/file.c Sun May 14 23:19:21 2000 > |+++ build/file.c Fri May 26 09:16:05 2000 > > lastsep()の所ですが、pathが増えてないので > 無限ループになってます。 うぐぅ。(;_;) あと、一つまずそうなところが。これは 1.4 にもありますね。 File.basename(string.taint, "").tainted? == false Index: file.c =================================================================== RCS file: /home/cvs/ruby/file.c,v retrieving revision 1.25 diff -u -2 -p -r1.25 file.c --- file.c 2000/05/25 05:55:00 1.25 +++ file.c 2000/05/27 17:54:36 @@ -67,4 +67,19 @@ char *strrchr _((const char*,const char) #include +#ifdef WINDOWS +#include "win32.h" +#endif + +#ifdef CharNext +#define next_char CharNext +#else +#define next_char(p) ((p) + 1) +#endif +#ifdef CharPrev +#define prev_char CharPrev +#else +#define prev_char(s, p) ((p) - 1) +#endif + #ifdef __EMX__ #define lstat stat @@ -1170,5 +1185,5 @@ rb_file_s_expand_path(argc, argv) { VALUE fname, dname; - char *s, *p; + char *s, *p, *t; char buf[MAXPATHLEN+2]; int tainted; @@ -1196,7 +1211,10 @@ rb_file_s_expand_path(argc, argv) s++; #endif + t = s; while (*s && !isdirsep(*s)) { - *p++ = *s++; + s = next_char(s); } + memcpy(p, t, s - t); + p += s - t; *p = '\0'; #ifdef HAVE_PWD_H @@ -1235,5 +1253,5 @@ rb_file_s_expand_path(argc, argv) } p = &buf[strlen(buf)]; - while (p > buf && *(p - 1) == '/') p--; + while (p > buf && (t = prev_char(buf, p), isdirsep(*t))) p = t; } else { @@ -1246,30 +1264,35 @@ rb_file_s_expand_path(argc, argv) *p = '/'; - for ( ; *s; s++) { + while (*s) { switch (*s) { case '.': - if (*(s+1)) { - switch (*++s) { - case '.': - if (*(s+1) == '\0' || isdirsep(*(s+1))) { - /* We must go back to the parent */ - if (isdirsep(*p) && p > buf) p--; - while (p > buf && !isdirsep(*p)) p--; - } - else { - *++p = '.'; - do *++p = '.'; while (*++s == '.'); - --s; - } - break; - case '/': + switch (*++s) { + case '\0': + break; + case '.': + if (*(s+1) == '\0' || isdirsep(*(s+1))) { + /* We must go back to the parent */ + if (isdirsep(*p) && p > buf) p = prev_char(buf, p); + while (p > buf && !isdirsep(*p)) p = prev_char(buf, p); + ++s; + } + else { + *(p = next_char(p)) = '.'; + do *++p = '.'; while (*++s == '.'); + } + break; + case '/': #if defined DOSISH - case '\\': + case '\\': #endif - if (!isdirsep(*p)) *++p = '/'; - break; - default: - *++p = '.'; *++p = *s; break; - } + if (!isdirsep(*p)) *(p = next_char(p)) = '/'; + ++s; + break; + default: + *(p = next_char(p)) = '.'; + t = next_char(s); + memcpy(++p, s, t - s); + s = t; + break; } break; @@ -1278,12 +1301,17 @@ rb_file_s_expand_path(argc, argv) case '\\': #endif - if (!isdirsep(*p)) *++p = '/'; break; + if (!isdirsep(*p)) *(p = next_char(p)) = '/'; + ++s; + break; default: - *++p = *s; + p = next_char(p); + t = next_char(s); + memcpy(p, s, t - s); + s = t; } } /* Place a \0 at end. If path ends with a "/", delete it */ - if (p == buf || !isdirsep(*p)) p++; + if (p == buf || !isdirsep(*p)) p = next_char(p); *p = '\0'; @@ -1316,4 +1344,30 @@ rmext(p, e) } +#ifdef DOSISH +static char* lastsep(path) + char *path; +{ + char *last = NULL; + while (*path) { + if (isdirsep(*path)) + last = path; + path = next_char(path); + } + return last; +} + +static int hasdrive(path) + char *path; +{ + if (isalpha(path[0]) && path[1] == ':') + return Qtrue; + else + return Qfalse; +} + +#else +#define lastsep(path) strrchr((path), '/') +#endif + static VALUE rb_file_s_basename(argc, argv) @@ -1329,19 +1383,22 @@ rb_file_s_basename(argc, argv) } name = STR2CSTR(fname); - p = strrchr(name, '/'); +#ifdef DOSISH + if (hasdrive(name)) + name += 2; +#endif + p = lastsep(name); if (!p) { - if (!NIL_P(fext)) { - f = rmext(name, ext); - if (f) return rb_str_new(name, f); + if (NIL_P(fext) || !(f = rmext(p, ext))) + return fname; + basename = rb_str_new(p, f); + } else { + p++; /* skip last `/' */ + if (NIL_P(fext) || !(f = rmext(p, ext))) { + basename = rb_str_new2(p); + } else { + basename = rb_str_new(p, f); } - return fname; } - p++; /* skip last `/' */ - if (!NIL_P(fext)) { - f = rmext(p, ext); - if (f) return rb_str_new(p, f); - } - basename = rb_str_new2(p); - if (OBJ_TAINTED(fname)) OBJ_TAINT(basename); + OBJ_INFECT(basename, fname); return basename; } @@ -1355,6 +1412,15 @@ rb_file_s_dirname(obj, fname) name = STR2CSTR(fname); - p = strrchr(name, '/'); + p = lastsep(name); if (!p) { +#ifdef DOSISH + if (hasdrive(name)) { + /* when "X:basename.ext" then return "X:." */ + dirname = rb_str_new(name, 3); + RSTRING(dirname)->ptr[2] = '.'; + OBJ_INFECT(dirname, fname); + return dirname; + } +#endif return rb_str_new2("."); } @@ -1362,5 +1428,5 @@ rb_file_s_dirname(obj, fname) p++; dirname = rb_str_new(name, p - name); - if (OBJ_TAINTED(fname)) OBJ_TAINT(dirname); + OBJ_INFECT(dirname, fname); return dirname; } @@ -1982,5 +2048,5 @@ path_check_1(path) return 0; } - s = strrchr(path, '/'); + s = lastsep(path); if (p) *p = '/'; if (!s || s == path) return 1; -- そうだ 強気に ちょっと インチキに☆彡 中田 "Bugるくらいがちょうどいいかも;-)" 伸悦