1647 |
return make_string (target, o - target); |
return make_string (target, o - target); |
1648 |
} |
} |
1649 |
|
|
|
#if 0 |
|
|
/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'. */ |
|
|
DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, |
|
|
"Convert FILENAME to absolute, and canonicalize it.\n\ |
|
|
Second arg DEFAULT is directory to start with if FILENAME is relative\n\ |
|
|
(does not start with slash); if DEFAULT is nil or missing,\n\ |
|
|
the current buffer's value of default-directory is used.\n\ |
|
|
Filenames containing `.' or `..' as components are simplified;\n\ |
|
|
initial `~/' expands to your home directory.\n\ |
|
|
See also the function `substitute-in-file-name'.") |
|
|
(name, defalt) |
|
|
Lisp_Object name, defalt; |
|
|
{ |
|
|
unsigned char *nm; |
|
|
|
|
|
register unsigned char *newdir, *p, *o; |
|
|
int tlen; |
|
|
unsigned char *target; |
|
|
struct passwd *pw; |
|
|
int lose; |
|
|
#ifdef VMS |
|
|
unsigned char * colon = 0; |
|
|
unsigned char * close = 0; |
|
|
unsigned char * slash = 0; |
|
|
unsigned char * brack = 0; |
|
|
int lbrack = 0, rbrack = 0; |
|
|
int dots = 0; |
|
|
#endif /* VMS */ |
|
|
|
|
|
CHECK_STRING (name, 0); |
|
|
|
|
|
#ifdef VMS |
|
|
/* Filenames on VMS are always upper case. */ |
|
|
name = Fupcase (name); |
|
|
#endif |
|
|
|
|
|
nm = XSTRING (name)->data; |
|
|
|
|
|
/* If nm is absolute, flush ...// and detect /./ and /../. |
|
|
If no /./ or /../ we can return right away. */ |
|
|
if ( |
|
|
nm[0] == '/' |
|
|
#ifdef VMS |
|
|
|| index (nm, ':') |
|
|
#endif /* VMS */ |
|
|
) |
|
|
{ |
|
|
p = nm; |
|
|
lose = 0; |
|
|
while (*p) |
|
|
{ |
|
|
if (p[0] == '/' && p[1] == '/' |
|
|
#ifdef APOLLO |
|
|
/* // at start of filename is meaningful on Apollo system. */ |
|
|
&& nm != p |
|
|
#endif /* APOLLO */ |
|
|
) |
|
|
nm = p + 1; |
|
|
if (p[0] == '/' && p[1] == '~') |
|
|
nm = p + 1, lose = 1; |
|
|
if (p[0] == '/' && p[1] == '.' |
|
|
&& (p[2] == '/' || p[2] == 0 |
|
|
|| (p[2] == '.' && (p[3] == '/' || p[3] == 0)))) |
|
|
lose = 1; |
|
|
#ifdef VMS |
|
|
if (p[0] == '\\') |
|
|
lose = 1; |
|
|
if (p[0] == '/') { |
|
|
/* if dev:[dir]/, move nm to / */ |
|
|
if (!slash && p > nm && (brack || colon)) { |
|
|
nm = (brack ? brack + 1 : colon + 1); |
|
|
lbrack = rbrack = 0; |
|
|
brack = 0; |
|
|
colon = 0; |
|
|
} |
|
|
slash = p; |
|
|
} |
|
|
if (p[0] == '-') |
|
|
#ifndef VMS4_4 |
|
|
/* VMS pre V4.4,convert '-'s in filenames. */ |
|
|
if (lbrack == rbrack) |
|
|
{ |
|
|
if (dots < 2) /* this is to allow negative version numbers */ |
|
|
p[0] = '_'; |
|
|
} |
|
|
else |
|
|
#endif /* VMS4_4 */ |
|
|
if (lbrack > rbrack && |
|
|
((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') && |
|
|
(p[1] == '.' || p[1] == ']' || p[1] == '>'))) |
|
|
lose = 1; |
|
|
#ifndef VMS4_4 |
|
|
else |
|
|
p[0] = '_'; |
|
|
#endif /* VMS4_4 */ |
|
|
/* count open brackets, reset close bracket pointer */ |
|
|
if (p[0] == '[' || p[0] == '<') |
|
|
lbrack++, brack = 0; |
|
|
/* count close brackets, set close bracket pointer */ |
|
|
if (p[0] == ']' || p[0] == '>') |
|
|
rbrack++, brack = p; |
|
|
/* detect ][ or >< */ |
|
|
if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<')) |
|
|
lose = 1; |
|
|
if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~') |
|
|
nm = p + 1, lose = 1; |
|
|
if (p[0] == ':' && (colon || slash)) |
|
|
/* if dev1:[dir]dev2:, move nm to dev2: */ |
|
|
if (brack) |
|
|
{ |
|
|
nm = brack + 1; |
|
|
brack = 0; |
|
|
} |
|
|
/* If /name/dev:, move nm to dev: */ |
|
|
else if (slash) |
|
|
nm = slash + 1; |
|
|
/* If node::dev:, move colon following dev */ |
|
|
else if (colon && colon[-1] == ':') |
|
|
colon = p; |
|
|
/* If dev1:dev2:, move nm to dev2: */ |
|
|
else if (colon && colon[-1] != ':') |
|
|
{ |
|
|
nm = colon + 1; |
|
|
colon = 0; |
|
|
} |
|
|
if (p[0] == ':' && !colon) |
|
|
{ |
|
|
if (p[1] == ':') |
|
|
p++; |
|
|
colon = p; |
|
|
} |
|
|
if (lbrack == rbrack) |
|
|
if (p[0] == ';') |
|
|
dots = 2; |
|
|
else if (p[0] == '.') |
|
|
dots++; |
|
|
#endif /* VMS */ |
|
|
p++; |
|
|
} |
|
|
if (!lose) |
|
|
{ |
|
|
#ifdef VMS |
|
|
if (index (nm, '/')) |
|
|
return build_string (sys_translate_unix (nm)); |
|
|
#endif /* VMS */ |
|
|
if (nm == XSTRING (name)->data) |
|
|
return name; |
|
|
return build_string (nm); |
|
|
} |
|
|
} |
|
|
|
|
|
/* Now determine directory to start with and put it in NEWDIR */ |
|
|
|
|
|
newdir = 0; |
|
|
|
|
|
if (nm[0] == '~') /* prefix ~ */ |
|
|
if (nm[1] == '/' |
|
|
#ifdef VMS |
|
|
|| nm[1] == ':' |
|
|
#endif /* VMS */ |
|
|
|| nm[1] == 0)/* ~/filename */ |
|
|
{ |
|
|
if (!(newdir = (unsigned char *) egetenv ("HOME"))) |
|
|
newdir = (unsigned char *) ""; |
|
|
nm++; |
|
|
#ifdef VMS |
|
|
nm++; /* Don't leave the slash in nm. */ |
|
|
#endif /* VMS */ |
|
|
} |
|
|
else /* ~user/filename */ |
|
|
{ |
|
|
/* Get past ~ to user */ |
|
|
unsigned char *user = nm + 1; |
|
|
/* Find end of name. */ |
|
|
unsigned char *ptr = (unsigned char *) index (user, '/'); |
|
|
int len = ptr ? ptr - user : strlen (user); |
|
|
#ifdef VMS |
|
|
unsigned char *ptr1 = index (user, ':'); |
|
|
if (ptr1 != 0 && ptr1 - user < len) |
|
|
len = ptr1 - user; |
|
|
#endif /* VMS */ |
|
|
/* Copy the user name into temp storage. */ |
|
|
o = (unsigned char *) alloca (len + 1); |
|
|
bcopy ((char *) user, o, len); |
|
|
o[len] = 0; |
|
|
|
|
|
/* Look up the user name. */ |
|
|
pw = (struct passwd *) getpwnam (o + 1); |
|
|
if (!pw) |
|
|
error ("\"%s\" isn't a registered user", o + 1); |
|
|
|
|
|
newdir = (unsigned char *) pw->pw_dir; |
|
|
|
|
|
/* Discard the user name from NM. */ |
|
|
nm += len; |
|
|
} |
|
|
|
|
|
if (nm[0] != '/' |
|
|
#ifdef VMS |
|
|
&& !index (nm, ':') |
|
|
#endif /* not VMS */ |
|
|
&& !newdir) |
|
|
{ |
|
|
if (NILP (defalt)) |
|
|
defalt = current_buffer->directory; |
|
|
CHECK_STRING (defalt, 1); |
|
|
newdir = XSTRING (defalt)->data; |
|
|
} |
|
|
|
|
|
/* Now concatenate the directory and name to new space in the stack frame */ |
|
|
|
|
|
tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1; |
|
|
target = (unsigned char *) alloca (tlen); |
|
|
*target = 0; |
|
|
|
|
|
if (newdir) |
|
|
{ |
|
|
#ifndef VMS |
|
|
if (nm[0] == 0 || nm[0] == '/') |
|
|
strcpy (target, newdir); |
|
|
else |
|
|
#endif |
|
|
file_name_as_directory (target, newdir); |
|
|
} |
|
|
|
|
|
strcat (target, nm); |
|
|
#ifdef VMS |
|
|
if (index (target, '/')) |
|
|
strcpy (target, sys_translate_unix (target)); |
|
|
#endif /* VMS */ |
|
|
|
|
|
/* Now canonicalize by removing /. and /foo/.. if they appear */ |
|
|
|
|
|
p = target; |
|
|
o = target; |
|
|
|
|
|
while (*p) |
|
|
{ |
|
|
#ifdef VMS |
|
|
if (*p != ']' && *p != '>' && *p != '-') |
|
|
{ |
|
|
if (*p == '\\') |
|
|
p++; |
|
|
*o++ = *p++; |
|
|
} |
|
|
else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) |
|
|
/* brackets are offset from each other by 2 */ |
|
|
{ |
|
|
p += 2; |
|
|
if (*p != '.' && *p != '-' && o[-1] != '.') |
|
|
/* convert [foo][bar] to [bar] */ |
|
|
while (o[-1] != '[' && o[-1] != '<') |
|
|
o--; |
|
|
else if (*p == '-' && *o != '.') |
|
|
*--p = '.'; |
|
|
} |
|
|
else if (p[0] == '-' && o[-1] == '.' && |
|
|
(p[1] == '.' || p[1] == ']' || p[1] == '>')) |
|
|
/* flush .foo.- ; leave - if stopped by '[' or '<' */ |
|
|
{ |
|
|
do |
|
|
o--; |
|
|
while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); |
|
|
if (p[1] == '.') /* foo.-.bar ==> bar. */ |
|
|
p += 2; |
|
|
else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ |
|
|
p++, o--; |
|
|
/* else [foo.-] ==> [-] */ |
|
|
} |
|
|
else |
|
|
{ |
|
|
#ifndef VMS4_4 |
|
|
if (*p == '-' && |
|
|
o[-1] != '[' && o[-1] != '<' && o[-1] != '.' && |
|
|
p[1] != ']' && p[1] != '>' && p[1] != '.') |
|
|
*p = '_'; |
|
|
#endif /* VMS4_4 */ |
|
|
*o++ = *p++; |
|
|
} |
|
|
#else /* not VMS */ |
|
|
if (*p != '/') |
|
|
{ |
|
|
*o++ = *p++; |
|
|
} |
|
|
else if (!strncmp (p, "//", 2) |
|
|
#ifdef APOLLO |
|
|
/* // at start of filename is meaningful in Apollo system. */ |
|
|
&& o != target |
|
|
#endif /* APOLLO */ |
|
|
) |
|
|
{ |
|
|
o = target; |
|
|
p++; |
|
|
} |
|
|
else if (p[0] == '/' && p[1] == '.' && |
|
|
(p[2] == '/' || p[2] == 0)) |
|
|
p += 2; |
|
|
else if (!strncmp (p, "/..", 3) |
|
|
/* `/../' is the "superroot" on certain file systems. */ |
|
|
&& o != target |
|
|
&& (p[3] == '/' || p[3] == 0)) |
|
|
{ |
|
|
while (o != target && *--o != '/') |
|
|
; |
|
|
#ifdef APOLLO |
|
|
if (o == target + 1 && o[-1] == '/' && o[0] == '/') |
|
|
++o; |
|
|
else |
|
|
#endif /* APOLLO */ |
|
|
if (o == target && *o == '/') |
|
|
++o; |
|
|
p += 3; |
|
|
} |
|
|
else |
|
|
{ |
|
|
*o++ = *p++; |
|
|
} |
|
|
#endif /* not VMS */ |
|
|
} |
|
|
|
|
|
return make_string (target, o - target); |
|
|
} |
|
|
#endif |
|
1650 |
|
|
1651 |
DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name, |
DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name, |
1652 |
Ssubstitute_in_file_name, 1, 1, 0, |
Ssubstitute_in_file_name, 1, 1, 0, |