Bug #5919 ยป file_encoding.diff
w/dir.c | ||
---|---|---|
{
|
||
VALUE d = *dir;
|
||
char *path, *pend;
|
||
long len;
|
||
rb_encoding *enc;
|
||
rb_secure(2);
|
||
FilePathValue(d);
|
||
path = RSTRING_PTR(d);
|
||
if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
|
||
enc = rb_enc_get(d);
|
||
RSTRING_GETMEM(d, path, len);
|
||
pend = path + len;
|
||
pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
|
||
if (pend - path < len) {
|
||
d = rb_str_subseq(d, 0, pend - path);
|
||
}
|
||
*dir = rb_str_encode_ospath(d);
|
||
... | ... | |
start = root = path;
|
||
flags |= FNM_SYSCASE;
|
||
#if defined DOSISH
|
||
root = rb_path_skip_prefix(root);
|
||
root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
|
||
#endif
|
||
if (root && *root == '/') root++;
|
w/ext/pathname/pathname.c | ||
---|---|---|
#include "ruby.h"
|
||
#include "ruby/encoding.h"
|
||
static VALUE rb_cPathname;
|
||
static ID id_at_path, id_to_path;
|
||
... | ... | |
StringValue(repl);
|
||
p = RSTRING_PTR(str);
|
||
ext = ruby_find_extname(p, &extlen);
|
||
extlen = RSTRING_LEN(str);
|
||
ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
|
||
if (ext == NULL) {
|
||
ext = p + RSTRING_LEN(str);
|
||
}
|
||
else if (extlen <= 1) {
|
||
ext += extlen;
|
||
}
|
||
str2 = rb_str_dup(str);
|
||
rb_str_resize(str2, ext-p);
|
||
str2 = rb_str_subseq(str, 0, ext-p);
|
||
rb_str_append(str2, repl);
|
||
OBJ_INFECT(str2, str);
|
||
return rb_class_new_instance(1, &str2, rb_obj_class(self));
|
w/file.c | ||
---|---|---|
#endif
|
||
#ifdef HAVE_READLINK
|
||
static VALUE rb_readlink(VALUE path);
|
||
/*
|
||
* call-seq:
|
||
* File.readlink(link_name) -> file_name
|
||
... | ... | |
static VALUE
|
||
rb_file_s_readlink(VALUE klass, VALUE path)
|
||
{
|
||
return rb_readlink(path);
|
||
}
|
||
static VALUE
|
||
rb_readlink(VALUE path)
|
||
{
|
||
char *buf;
|
||
int size = 100;
|
||
ssize_t rv;
|
||
... | ... | |
#define istrailinggarbage(x) 0
|
||
#endif
|
||
#ifndef CharNext /* defined as CharNext[AW] on Windows. */
|
||
# define CharNext(p) ((p) + 1)
|
||
#endif
|
||
#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
|
||
#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
|
||
#if defined(DOSISH_UNC)
|
||
#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
|
||
... | ... | |
#endif
|
||
static inline char *
|
||
skiproot(const char *path)
|
||
skiproot(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
#ifdef DOSISH_DRIVE_LETTER
|
||
if (has_drive_letter(path)) path += 2;
|
||
if (path + 2 <= end && has_drive_letter(path)) path += 2;
|
||
#endif
|
||
while (isdirsep(*path)) path++;
|
||
while (path < end && isdirsep(*path)) path++;
|
||
return (char *)path;
|
||
}
|
||
#define nextdirsep rb_path_next
|
||
#define nextdirsep rb_enc_path_next
|
||
char *
|
||
rb_path_next(const char *s)
|
||
rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
|
||
{
|
||
while (*s && !isdirsep(*s)) {
|
||
s = CharNext(s);
|
||
while (s < e && !isdirsep(*s)) {
|
||
Inc(s, e, enc);
|
||
}
|
||
return (char *)s;
|
||
}
|
||
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
|
||
#define skipprefix rb_path_skip_prefix
|
||
#define skipprefix rb_enc_path_skip_prefix
|
||
#else
|
||
#define skipprefix(path) (path)
|
||
#define skipprefix(path, end, enc) (path)
|
||
#endif
|
||
char *
|
||
rb_path_skip_prefix(const char *path)
|
||
rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
|
||
#ifdef DOSISH_UNC
|
||
if (isdirsep(path[0]) && isdirsep(path[1])) {
|
||
if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
|
||
path += 2;
|
||
while (isdirsep(*path)) path++;
|
||
if (*(path = nextdirsep(path)) && path[1] && !isdirsep(path[1]))
|
||
path = nextdirsep(path + 1);
|
||
while (path < end && isdirsep(*path)) path++;
|
||
if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
|
||
path = rb_enc_path_next(path + 1, end, enc);
|
||
return (char *)path;
|
||
}
|
||
#endif
|
||
... | ... | |
}
|
||
static inline char *
|
||
skipprefixroot(const char *path)
|
||
skipprefixroot(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
|
||
char *p = skipprefix(path);
|
||
char *p = skipprefix(path, end, enc);
|
||
while (isdirsep(*p)) p++;
|
||
return p;
|
||
#else
|
||
return skiproot(path);
|
||
return skiproot(path, end, enc);
|
||
#endif
|
||
}
|
||
#define strrdirsep rb_path_last_separator
|
||
#define strrdirsep rb_enc_path_last_separator
|
||
char *
|
||
rb_path_last_separator(const char *path)
|
||
rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
char *last = NULL;
|
||
while (*path) {
|
||
while (path < end) {
|
||
if (isdirsep(*path)) {
|
||
const char *tmp = path++;
|
||
while (isdirsep(*path)) path++;
|
||
if (!*path) break;
|
||
while (path < end && isdirsep(*path)) path++;
|
||
if (path >= end) break;
|
||
last = (char *)tmp;
|
||
}
|
||
else {
|
||
path = CharNext(path);
|
||
Inc(path, end, enc);
|
||
}
|
||
}
|
||
return last;
|
||
}
|
||
static char *
|
||
chompdirsep(const char *path)
|
||
chompdirsep(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
while (*path) {
|
||
if (isdirsep(*path)) {
|
||
const char *last = path++;
|
||
while (isdirsep(*path)) path++;
|
||
if (!*path) return (char *)last;
|
||
while (path < end && isdirsep(*path)) path++;
|
||
if (path >= end) return (char *)last;
|
||
}
|
||
else {
|
||
path = CharNext(path);
|
||
Inc(path, end, enc);
|
||
}
|
||
}
|
||
return (char *)path;
|
||
}
|
||
char *
|
||
rb_path_end(const char *path)
|
||
rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
if (isdirsep(*path)) path++;
|
||
return chompdirsep(path);
|
||
if (path < end && isdirsep(*path)) path++;
|
||
return chompdirsep(path, end, enc);
|
||
}
|
||
#if USE_NTFS
|
||
static char *
|
||
ntfs_tail(const char *path)
|
||
ntfs_tail(const char *path, const char *end, rb_encoding *enc)
|
||
{
|
||
while (*path == '.') path++;
|
||
while (*path && *path != ':') {
|
||
while (path < end && *path == '.') path++;
|
||
while (path < end && *path != ':') {
|
||
if (istrailinggarbage(*path)) {
|
||
const char *last = path++;
|
||
while (istrailinggarbage(*path)) path++;
|
||
if (!*path || *path == ':') return (char *)last;
|
||
while (path < end && istrailinggarbage(*path)) path++;
|
||
if (path >= end || *path == ':') return (char *)last;
|
||
}
|
||
else if (isdirsep(*path)) {
|
||
const char *last = path++;
|
||
while (isdirsep(*path)) path++;
|
||
if (!*path) return (char *)last;
|
||
while (path < end && isdirsep(*path)) path++;
|
||
if (path >= end) return (char *)last;
|
||
if (*path == ':') path++;
|
||
}
|
||
else {
|
||
path = CharNext(path);
|
||
Inc(path, end, enc);
|
||
}
|
||
}
|
||
return (char *)path;
|
||
... | ... | |
const char *dir;
|
||
char *buf;
|
||
#if defined DOSISH || defined __CYGWIN__
|
||
char *p;
|
||
char *p, *bend;
|
||
#endif
|
||
long dirlen;
|
||
rb_encoding *enc;
|
||
if (!user || !*user) {
|
||
if (!(dir = getenv("HOME"))) {
|
||
... | ... | |
}
|
||
dirlen = strlen(pwPtr->pw_dir);
|
||
rb_str_resize(result, dirlen);
|
||
strcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir);
|
||
memcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir, dirlen + 1);
|
||
endpwent();
|
||
#else
|
||
return Qnil;
|
||
#endif
|
||
}
|
||
enc = rb_filesystem_encoding();
|
||
rb_enc_associate(result, enc);
|
||
#if defined DOSISH || defined __CYGWIN__
|
||
for (p = buf; *p; p = CharNext(p)) {
|
||
for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
|
||
if (*p == '\\') {
|
||
*p = '/';
|
||
}
|
||
}
|
||
#endif
|
||
rb_enc_associate_index(result, rb_filesystem_encindex());
|
||
return result;
|
||
}
|
||
static VALUE
|
||
file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
|
||
{
|
||
const char *s, *b;
|
||
const char *s, *b, *fend;
|
||
char *buf, *p, *pend, *root;
|
||
size_t buflen, dirlen, bdiff;
|
||
int tainted;
|
||
rb_encoding *enc, *fsenc = rb_filesystem_encoding();
|
||
s = StringValuePtr(fname);
|
||
fend = s + RSTRING_LEN(fname);
|
||
enc = rb_enc_get(fname);
|
||
BUFINIT();
|
||
tainted = OBJ_TAINTED(fname);
|
||
... | ... | |
if (*++s) ++s;
|
||
}
|
||
else {
|
||
s = nextdirsep(b = s);
|
||
s = nextdirsep(b = s, fend, enc);
|
||
userlen = s - b;
|
||
BUFCHECK(bdiff + userlen >= buflen);
|
||
memcpy(p, b, userlen);
|
||
... | ... | |
BUFCHECK(dirlen > buflen);
|
||
strcpy(buf, dir);
|
||
xfree(dir);
|
||
rb_enc_associate_index(result, rb_filesystem_encindex());
|
||
rb_enc_associate(result, enc = fsenc);
|
||
}
|
||
else
|
||
rb_enc_associate(result, rb_enc_check(result, fname));
|
||
p = chompdirsep(skiproot(buf));
|
||
rb_enc_associate(result, enc = rb_enc_check(result, fname));
|
||
p = chompdirsep(skiproot(buf, pend, enc), pend, enc);
|
||
s += 2;
|
||
}
|
||
}
|
||
... | ... | |
}
|
||
else {
|
||
char *dir = my_getcwd();
|
||
char *cwdp;
|
||
VALUE dirname = Qnil;
|
||
tainted = 1;
|
||
dirlen = strlen(dir);
|
||
cwdp = dir;
|
||
if (enc != fsenc) {
|
||
rb_encoding *direnc = rb_enc_check(fname, dirname = rb_enc_str_new(dir, dirlen, fsenc));
|
||
if (direnc != fsenc) {
|
||
dirname = rb_str_conv_enc(dirname, fsenc, direnc);
|
||
RSTRING_GETMEM(dirname, cwdp, dirlen);
|
||
}
|
||
}
|
||
rb_enc_associate(result, enc);
|
||
BUFCHECK(dirlen > buflen);
|
||
strcpy(buf, dir);
|
||
strcpy(buf, cwdp);
|
||
xfree(dir);
|
||
rb_enc_associate_index(result, rb_filesystem_encindex());
|
||
if (!NIL_P(dirname)) rb_str_resize(dirname, 0);
|
||
}
|
||
#if defined DOSISH || defined __CYGWIN__
|
||
if (isdirsep(*s)) {
|
||
/* specified full path, but not drive letter nor UNC */
|
||
/* we need to get the drive letter or UNC share name */
|
||
p = skipprefix(buf);
|
||
p = skipprefix(buf, pend, enc);
|
||
}
|
||
else
|
||
#endif
|
||
p = chompdirsep(skiproot(buf));
|
||
p = chompdirsep(skiproot(buf, pend, enc), pend, enc);
|
||
}
|
||
else {
|
||
size_t len;
|
||
... | ... | |
rb_str_set_len(result, p-buf+1);
|
||
BUFCHECK(bdiff + 1 >= buflen);
|
||
p[1] = 0;
|
||
root = skipprefix(buf);
|
||
root = skipprefix(buf, p+1, enc);
|
||
b = s;
|
||
while (*s) {
|
||
... | ... | |
/* We must go back to the parent */
|
||
char *n;
|
||
*p = '\0';
|
||
if (!(n = strrdirsep(root))) {
|
||
if (!(n = strrdirsep(root, p, enc))) {
|
||
*p = '/';
|
||
}
|
||
else {
|
||
... | ... | |
--s;
|
||
case ' ': {
|
||
const char *e = s;
|
||
while (istrailinggarbage(*s)) s++;
|
||
while (s < fend && istrailinggarbage(*s)) s++;
|
||
if (!*s) {
|
||
s = e;
|
||
goto endpath;
|
||
... | ... | |
b = ++s;
|
||
break;
|
||
default:
|
||
s = CharNext(s);
|
||
Inc(s, fend, enc);
|
||
break;
|
||
}
|
||
}
|
||
... | ... | |
BUFCHECK(bdiff + (s-b) >= buflen);
|
||
memcpy(++p, b, s-b);
|
||
p += s-b;
|
||
rb_str_set_len(result, p-buf);
|
||
}
|
||
if (p == skiproot(buf) - 1) p++;
|
||
if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
|
||
#if USE_NTFS
|
||
*p = '\0';
|
||
if ((s = strrdirsep(b = buf)) != 0 && !strpbrk(s, "*?")) {
|
||
if ((s = strrdirsep(b = buf, p, enc)) != 0 && !strpbrk(s, "*?")) {
|
||
VALUE tmp, v;
|
||
size_t len;
|
||
WIN32_FIND_DATA wfd;
|
||
rb_encoding *enc;
|
||
WCHAR *wstr;
|
||
WIN32_FIND_DATAW wfd;
|
||
HANDLE h;
|
||
#ifdef __CYGWIN__
|
||
#ifdef HAVE_CYGWIN_CONV_PATH
|
||
... | ... | |
}
|
||
*p = '/';
|
||
#endif
|
||
h = FindFirstFile(b, &wfd);
|
||
rb_str_set_len(result, p - buf + strlen(p));
|
||
enc = rb_enc_get(result);
|
||
tmp = result;
|
||
if (enc != rb_utf8_encoding() && rb_enc_str_coderange(result) != ENC_CODERANGE_7BIT) {
|
||
tmp = rb_str_encode_ospath(result);
|
||
}
|
||
len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
|
||
wstr = ALLOCV_N(WCHAR, v, len);
|
||
MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, wstr, len);
|
||
if (tmp != result) rb_str_resize(tmp, 0);
|
||
h = FindFirstFileW(wstr, &wfd);
|
||
ALLOCV_END(v);
|
||
if (h != INVALID_HANDLE_VALUE) {
|
||
size_t wlen;
|
||
FindClose(h);
|
||
len = strlen(wfd.cFileName);
|
||
len = lstrlenW(wfd.cFileName);
|
||
#ifdef __CYGWIN__
|
||
if (lnk_added && len > 4 &&
|
||
STRCASECMP(wfd.cFileName + len - 4, ".lnk") == 0) {
|
||
wfd.cFileName[len -= 4] = '\0';
|
||
wcsicmp(wfd.cFileName + len - 4, L".lnk") == 0) {
|
||
wfd.cFileName[len -= 4] = L'\0';
|
||
}
|
||
#else
|
||
p = (char *)s;
|
||
#endif
|
||
++p;
|
||
wlen = (int)len;
|
||
len = WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, NULL, 0, NULL, NULL);
|
||
BUFCHECK(bdiff + len >= buflen);
|
||
memcpy(p, wfd.cFileName, len + 1);
|
||
WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, p, len + 1, NULL, NULL);
|
||
if (tmp != result) {
|
||
rb_str_buf_cat(tmp, p, len);
|
||
tmp = rb_str_encode(tmp, rb_enc_from_encoding(enc), 0, Qnil);
|
||
len = RSTRING_LEN(tmp);
|
||
BUFCHECK(bdiff + len >= buflen);
|
||
memcpy(p, RSTRING_PTR(tmp), len);
|
||
rb_str_resize(tmp, 0);
|
||
}
|
||
p += len;
|
||
}
|
||
#ifdef __CYGWIN__
|
||
... | ... | |
}
|
||
static void
|
||
realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopcheck, int strict, int last)
|
||
realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE loopcheck, int strict, int last)
|
||
{
|
||
const char *pend = unresolved + strlen(unresolved);
|
||
rb_encoding *enc = rb_enc_get(*resolvedp);
|
||
ID resolving;
|
||
CONST_ID(resolving, "resolving");
|
||
while (*unresolved) {
|
||
char *testname = unresolved;
|
||
char *unresolved_firstsep = rb_path_next(unresolved);
|
||
long testnamelen = unresolved_firstsep - unresolved;
|
||
char *unresolved_nextname = unresolved_firstsep;
|
||
while (isdirsep(*unresolved_nextname)) unresolved_nextname++;
|
||
while (unresolved < pend) {
|
||
const char *testname = unresolved;
|
||
const char *unresolved_firstsep = rb_enc_path_next(unresolved, pend, enc);
|
||
long testnamelen = unresolved_firstsep - unresolved;
|
||
const char *unresolved_nextname = unresolved_firstsep;
|
||
while (unresolved_nextname < pend && isdirsep(*unresolved_nextname))
|
||
unresolved_nextname++;
|
||
unresolved = unresolved_nextname;
|
||
if (testnamelen == 1 && testname[0] == '.') {
|
||
}
|
||
else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
|
||
if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
|
||
char *resolved_names = RSTRING_PTR(*resolvedp) + *prefixlenp;
|
||
char *lastsep = rb_path_last_separator(resolved_names);
|
||
const char *resolved_str = RSTRING_PTR(*resolvedp);
|
||
const char *resolved_names = resolved_str + *prefixlenp;
|
||
const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
|
||
long len = lastsep ? lastsep - resolved_names : 0;
|
||
rb_str_resize(*resolvedp, *prefixlenp + len);
|
||
}
|
||
... | ... | |
}
|
||
#ifdef HAVE_READLINK
|
||
if (S_ISLNK(sbuf.st_mode)) {
|
||
volatile VALUE link;
|
||
char *link_prefix, *link_names;
|
||
VALUE link;
|
||
const char *link_prefix, *link_names;
|
||
long link_prefixlen;
|
||
rb_hash_aset(loopcheck, testpath, ID2SYM(resolving));
|
||
link = rb_file_s_readlink(rb_cFile, testpath);
|
||
link = rb_readlink(testpath);
|
||
link_prefix = RSTRING_PTR(link);
|
||
link_names = skipprefixroot(link_prefix);
|
||
link_prefixlen = link_names - link_prefix;
|
||
if (link_prefixlen == 0) {
|
||
realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
|
||
}
|
||
else {
|
||
*resolvedp = rb_str_new(link_prefix, link_prefixlen);
|
||
*prefixlenp = link_prefixlen;
|
||
realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
|
||
}
|
||
rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
|
||
link_names = skipprefixroot(link_prefix, link_prefix + RSTRING_LEN(link), rb_enc_get(link));
|
||
link_prefixlen = link_names - link_prefix;
|
||
if (link_prefixlen > 0) {
|
||
rb_encoding *enc, *linkenc = rb_enc_get(link);
|
||
link = rb_str_subseq(link, 0, link_prefixlen);
|
||
enc = rb_enc_check(*resolvedp, link);
|
||
if (enc != linkenc) link = rb_str_conv_enc(link, linkenc, enc);
|
||
*resolvedp = link;
|
||
*prefixlenp = link_prefixlen;
|
||
}
|
||
realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
|
||
rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
|
||
}
|
||
else
|
||
#endif
|
||
... | ... | |
VALUE loopcheck;
|
||
volatile VALUE curdir = Qnil;
|
||
rb_encoding *enc;
|
||
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
|
||
char *ptr, *prefixptr = NULL;
|
||
char *ptr, *prefixptr = NULL, *pend;
|
||
long len;
|
||
rb_secure(2);
|
||
... | ... | |
basedir = rb_str_dup_frozen(basedir);
|
||
}
|
||
ptr = RSTRING_PTR(unresolved_path);
|
||
path_names = skipprefixroot(ptr);
|
||
RSTRING_GETMEM(unresolved_path, ptr, len);
|
||
path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path));
|
||
if (ptr != path_names) {
|
||
resolved = rb_enc_str_new(ptr, path_names - ptr,
|
||
rb_enc_get(unresolved_path));
|
||
resolved = rb_str_subseq(unresolved_path, 0, path_names - ptr);
|
||
goto root_found;
|
||
}
|
||
if (!NIL_P(basedir)) {
|
||
ptr = RSTRING_PTR(basedir);
|
||
basedir_names = skipprefixroot(ptr);
|
||
RSTRING_GETMEM(basedir, ptr, len);
|
||
basedir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(basedir));
|
||
if (ptr != basedir_names) {
|
||
resolved = rb_enc_str_new(ptr, basedir_names - ptr,
|
||
rb_enc_get(basedir));
|
||
goto root_found;
|
||
resolved = rb_str_subseq(basedir, 0, basedir_names - ptr);
|
||
goto root_found;
|
||
}
|
||
}
|
||
curdir = rb_dir_getwd();
|
||
ptr = RSTRING_PTR(curdir);
|
||
curdir_names = skipprefixroot(ptr);
|
||
resolved = rb_enc_str_new(ptr, curdir_names - ptr, rb_enc_get(curdir));
|
||
RSTRING_GETMEM(curdir, ptr, len);
|
||
curdir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(curdir));
|
||
resolved = rb_str_subseq(curdir, 0, curdir_names - ptr);
|
||
root_found:
|
||
prefixptr = RSTRING_PTR(resolved);
|
||
prefixlen = RSTRING_LEN(resolved);
|
||
ptr = chompdirsep(prefixptr);
|
||
if (*ptr) {
|
||
RSTRING_GETMEM(resolved, prefixptr, prefixlen);
|
||
pend = prefixptr + prefixlen;
|
||
enc = rb_enc_get(resolved);
|
||
ptr = chompdirsep(prefixptr, pend, enc);
|
||
if (ptr < pend) {
|
||
prefixlen = ++ptr - prefixptr;
|
||
rb_str_set_len(resolved, prefixlen);
|
||
}
|
||
... | ... | |
if (*prefixptr == FILE_ALT_SEPARATOR) {
|
||
*prefixptr = '/';
|
||
}
|
||
prefixptr = CharNext(prefixptr);
|
||
Inc(prefixptr, pend, enc);
|
||
}
|
||
#endif
|
||
... | ... | |
}
|
||
const char *
|
||
ruby_find_basename(const char *name, long *baselen, long *alllen)
|
||
ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
|
||
{
|
||
const char *p, *q, *e;
|
||
const char *p, *q, *e, *end;
|
||
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
|
||
const char *root;
|
||
#endif
|
||
long f = 0, n = -1;
|
||
name = skipprefix(name);
|
||
end = name + *alllen;
|
||
name = skipprefix(name, end, enc);
|
||
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
|
||
root = name;
|
||
#endif
|
||
... | ... | |
#endif
|
||
}
|
||
else {
|
||
if (!(p = strrdirsep(name))) {
|
||
if (!(p = strrdirsep(name, end, enc))) {
|
||
p = name;
|
||
}
|
||
else {
|
||
while (isdirsep(*p)) p++; /* skip last / */
|
||
}
|
||
#if USE_NTFS
|
||
n = ntfs_tail(p) - p;
|
||
n = ntfs_tail(p, end, enc) - p;
|
||
#else
|
||
n = chompdirsep(p) - p;
|
||
n = chompdirsep(p, end, enc) - p;
|
||
#endif
|
||
for (q = p; q - p < n && *q == '.'; q++);
|
||
for (e = 0; q - p < n; q = CharNext(q)) {
|
||
for (e = 0; q - p < n; Inc(q, end, enc)) {
|
||
if (*q == '.') e = q;
|
||
}
|
||
if (e) f = e - p;
|
||
... | ... | |
VALUE fname, fext, basename;
|
||
const char *name, *p;
|
||
long f, n;
|
||
rb_encoding *enc;
|
||
if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
|
||
rb_encoding *enc;
|
||
... | ... | |
}
|
||
}
|
||
FilePathStringValue(fname);
|
||
if (!NIL_P(fext)) rb_enc_check(fname, fext);
|
||
if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
|
||
if (!NIL_P(fext)) enc = rb_enc_check(fname, fext);
|
||
else enc = rb_enc_get(fname);
|
||
if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname)))
|
||
return rb_str_new_shared(fname);
|
||
p = ruby_find_basename(name, &f, &n);
|
||
p = ruby_enc_find_basename(name, &f, &n, enc);
|
||
if (n >= 0) {
|
||
if (NIL_P(fext) || !(f = rmext(p, f, n, StringValueCStr(fext)))) {
|
||
f = n;
|
||
... | ... | |
VALUE
|
||
rb_file_dirname(VALUE fname)
|
||
{
|
||
const char *name, *root, *p;
|
||
const char *name, *root, *p, *end;
|
||
VALUE dirname;
|
||
rb_encoding *enc;
|
||
FilePathStringValue(fname);
|
||
name = StringValueCStr(fname);
|
||
root = skiproot(name);
|
||
end = name + RSTRING_LEN(fname);
|
||
enc = rb_enc_get(fname);
|
||
root = skiproot(name, end, enc);
|
||
#ifdef DOSISH_UNC
|
||
if (root > name + 1 && isdirsep(*name))
|
||
root = skipprefix(name = root - 2);
|
||
root = skipprefix(name = root - 2, end, enc);
|
||
#else
|
||
if (root > name + 1)
|
||
name = root - 1;
|
||
#endif
|
||
p = strrdirsep(root);
|
||
p = strrdirsep(root, end, enc);
|
||
if (!p) {
|
||
p = root;
|
||
}
|
||
... | ... | |
return rb_usascii_str_new2(".");
|
||
#ifdef DOSISH_DRIVE_LETTER
|
||
if (has_drive_letter(name) && isdirsep(*(name + 2))) {
|
||
const char *top = skiproot(name + 2);
|
||
const char *top = skiproot(name + 2, end, enc);
|
||
dirname = rb_str_new(name, 3);
|
||
rb_str_cat(dirname, top, p - top);
|
||
}
|
||
... | ... | |
*
|
||
*/
|
||
const char *
|
||
ruby_find_extname(const char *name, long *len)
|
||
ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
|
||
{
|
||
const char *p, *e;
|
||
const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
|
||
p = strrdirsep(name); /* get the last path component */
|
||
p = strrdirsep(name, end, enc); /* get the last path component */
|
||
if (!p)
|
||
p = name;
|
||
else
|
||
... | ... | |
#endif
|
||
else if (isdirsep(*p))
|
||
break;
|
||
p = CharNext(p);
|
||
Inc(p, end, enc);
|
||
}
|
||
if (len) {
|
||
... | ... | |
FilePathStringValue(fname);
|
||
name = StringValueCStr(fname);
|
||
e = ruby_find_extname(name, &len);
|
||
len = RSTRING_LEN(fname);
|
||
e = ruby_enc_find_extname(name, &len, rb_enc_get(fname));
|
||
if (len <= 1)
|
||
return rb_str_new(0, 0);
|
||
extname = rb_str_new(e, len); /* keep the dot, too! */
|
||
rb_enc_copy(extname, fname);
|
||
extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */
|
||
OBJ_INFECT(extname, fname);
|
||
return extname;
|
||
}
|
||
... | ... | |
len = 1;
|
||
for (i=0; i<RARRAY_LEN(ary); i++) {
|
||
if (TYPE(RARRAY_PTR(ary)[i]) == T_STRING) {
|
||
len += RSTRING_LEN(RARRAY_PTR(ary)[i]);
|
||
tmp = RARRAY_PTR(ary)[i];
|
||
if (RB_TYPE_P(tmp, T_STRING)) {
|
||
len += RSTRING_LEN(tmp);
|
||
}
|
||
else {
|
||
len += 10;
|
||
... | ... | |
}
|
||
result = rb_str_buf_new(len);
|
||
OBJ_INFECT(result, ary);
|
||
RBASIC(result)->klass = 0;
|
||
len = 0;
|
||
for (i=0; i<RARRAY_LEN(ary); i++) {
|
||
tmp = RARRAY_PTR(ary)[i];
|
||
switch (TYPE(tmp)) {
|
||
... | ... | |
args[1] = sep;
|
||
tmp = rb_exec_recursive(file_inspect_join, ary, (VALUE)args);
|
||
}
|
||
break;
|
||
if (0)
|
||
default:
|
||
FilePathStringValue(tmp);
|
||
if (RBASIC(result)->klass) rb_raise(rb_eRuntimeError, "File.join reentered");
|
||
}
|
||
name = StringValueCStr(result);
|
||
if (i == 0) {
|
||
rb_enc_copy(result, tmp);
|
||
}
|
||
else if (!NIL_P(sep)) {
|
||
tail = chompdirsep(name);
|
||
name = RSTRING_PTR(result);
|
||
tail = chompdirsep(name + len, name + RSTRING_LEN(result), rb_enc_get(result));
|
||
if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
|
||
rb_str_set_len(result, tail - name);
|
||
}
|
||
... | ... | |
}
|
||
rb_str_buf_append(result, tmp);
|
||
}
|
||
RBASIC(result)->klass = rb_cString;
|
||
return result;
|
||
}
|
||
... | ... | |
{
|
||
struct stat st;
|
||
const char *p0 = StringValueCStr(path);
|
||
const char *e0;
|
||
rb_encoding *enc;
|
||
char *p = 0, *s;
|
||
if (!rb_is_absolute_path(p0)) {
|
||
... | ... | |
path = newpath;
|
||
p0 = RSTRING_PTR(path);
|
||
}
|
||
e0 = p0 + RSTRING_LEN(path);
|
||
enc = rb_enc_get(path);
|
||
for (;;) {
|
||
#ifndef S_IWOTH
|
||
# define S_IWOTH 002
|
||
... | ... | |
RB_GC_GUARD(path);
|
||
return 0;
|
||
}
|
||
s = strrdirsep(p0);
|
||
s = strrdirsep(p0, e0, enc);
|
||
if (p) *p = '/';
|
||
if (!s || s == p0) return 1;
|
||
p = s;
|
||
e0 = p;
|
||
*p = '\0';
|
||
}
|
||
}
|
w/include/ruby/encoding.h | ||
---|---|---|
/* start, ptr, end, encoding -> prev_char */
|
||
#define rb_enc_prev_char(s,p,e,enc) ((char *)onigenc_get_prev_char_head((enc),(UChar*)(s),(UChar*)(p),(UChar*)(e)))
|
||
/* start, ptr, end, encoding -> next_char */
|
||
/* ptr, end, encoding -> next_char */
|
||
#define rb_enc_next_char(p,e,enc) ((char *)onigenc_get_prev_char_head((enc),(UChar*)(p),(UChar*)(e)))
|
||
#define rb_enc_left_char_head(s,p,e,enc) ((char *)onigenc_get_left_adjust_char_head((enc),(UChar*)(s),(UChar*)(p),(UChar*)(e)))
|
||
#define rb_enc_right_char_head(s,p,e,enc) ((char *)onigenc_get_right_adjust_char_head((enc),(UChar*)(s),(UChar*)(p),(UChar*)(e)))
|
||
#define rb_enc_step_back(s,p,e,n,enc) ((char *)onigenc_step_back((enc),(UChar*)(s),(UChar*)(p),(UChar*)(e),(int)(n)))
|
||
#define rb_enc_step(p,e,n,enc) ((char *)onigenc_step((enc),(UChar*)(p),(UChar*)(e),(int)(n)))
|
||
/* ptr, ptr, encoding -> newline_or_not */
|
||
#define rb_enc_is_newline(p,end,enc) ONIGENC_IS_MBC_NEWLINE((enc),(UChar*)(p),(UChar*)(end))
|
||
... | ... | |
void rb_enc_set_default_internal(VALUE encoding);
|
||
VALUE rb_locale_charmap(VALUE klass);
|
||
long rb_memsearch(const void*,long,const void*,long,rb_encoding*);
|
||
char *rb_enc_path_next(const char *,const char *,rb_encoding*);
|
||
char *rb_enc_path_skip_prefix(const char *,const char *,rb_encoding*);
|
||
char *rb_enc_path_last_separator(const char *,const char *,rb_encoding*);
|
||
char *rb_enc_path_end(const char *,const char *,rb_encoding*);
|
||
const char *ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc);
|
||
const char *ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc);
|
||
RUBY_EXTERN VALUE rb_cEncoding;
|
||
#define ENC_DUMMY_FLAG (1<<24)
|
w/include/ruby/intern.h | ||
---|---|---|
VALUE rb_file_directory_p(VALUE,VALUE);
|
||
VALUE rb_str_encode_ospath(VALUE);
|
||
int rb_is_absolute_path(const char *);
|
||
const char *ruby_find_basename(const char *name, long *baselen, long *alllen);
|
||
const char *ruby_find_extname(const char *name, long *len);
|
||
/* gc.c */
|
||
void ruby_set_stack_size(size_t);
|
||
NORETURN(void rb_memerror(void));
|
w/test/pathname/test_pathname.rb | ||
---|---|---|
#!/usr/bin/env ruby
|
||
require 'test/unit'
|
||
require 'pathname'
|
||
... | ... | |
if DOSISH
|
||
defassert(:del_trailing_separator, "a", "a\\")
|
||
require 'Win32API'
|
||
if Win32API.new('kernel32', 'GetACP', nil, 'L').call == 932
|
||
defassert(:del_trailing_separator, "\225\\", "\225\\\\") # SJIS
|
||
end
|
||
defassert(:del_trailing_separator, "\225\\".force_encoding("cp932"), "\225\\\\".force_encoding("cp932"))
|
||
defassert(:del_trailing_separator, "\225".force_encoding("cp437"), "\225\\\\".force_encoding("cp437"))
|
||
end
|
||
def test_plus
|
w/test/ruby/test_file_exhaustive.rb | ||
---|---|---|
require "tmpdir"
|
||
class TestFileExhaustive < Test::Unit::TestCase
|
||
DRIVE = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i]
|
||
def assert_incompatible_encoding
|
||
d = "\u{3042}\u{3044}".encode("utf-16le")
|
||
assert_raise(Encoding::CompatibilityError) {yield d}
|
||
... | ... | |
assert_match(/\Ac:\//i, File.expand_path('c:foo', 'd:/bar'))
|
||
assert_match(%r'\Ac:/bar/foo\z'i, File.expand_path('c:foo', 'c:/bar'))
|
||
end
|
||
if drive = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i]
|
||
if DRIVE
|
||
assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar"))
|
||
assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar"))
|
||
assert_match(%r"\A#{drive}/foo\z"i, File.expand_path('/foo'))
|
||
assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo'))
|
||
else
|
||
assert_equal("/foo", File.expand_path('/foo'))
|
||
end
|
||
if Encoding.find("filesystem") == Encoding::CP1251
|
||
a = "/\u3042\u3044\u3046\u3048\u304a".encode("cp932")
|
||
else
|
||
a = "/\u043f\u0440\u0438\u0432\u0435\u0442".encode("cp1251")
|
||
end
|
||
a = "C:" + a if DRIVE
|
||
assert_equal(a, File.expand_path(a))
|
||
if DRIVE
|
||
a = "C:/\225\\\\"
|
||
[%W"cp437 C:/\225", %W"cp932 C:/\225\\"].each do |cp, expected|
|
||
assert_equal(expected.force_encoding(cp), File.expand_path(a.dup.force_encoding(cp)), cp)
|
||
end
|
||
end
|
||
assert_kind_of(String, File.expand_path("~")) if ENV["HOME"]
|
||
assert_raise(ArgumentError) { File.expand_path("~foo_bar_baz_unknown_user_wahaha") }
|
||
assert_raise(ArgumentError) { File.expand_path("~foo_bar_baz_unknown_user_wahaha", "/") }
|
||
... | ... | |
assert_equal(basename, File.basename(@file + ".", ".*"))
|
||
assert_equal(basename, File.basename(@file + "::$DATA", ".*"))
|
||
end
|
||
if DRIVE
|
||
a = "C:/\225\\\\"
|
||
[%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected|
|
||
assert_equal(expected.force_encoding(cp), File.basename(a.dup.force_encoding(cp)), cp)
|
||
end
|
||
end
|
||
assert_incompatible_encoding {|d| File.basename(d)}
|
||
assert_incompatible_encoding {|d| File.basename(d, ".*")}
|