Mercurial > emacs
comparison src/fileio.c @ 94037:d864a5e618e0
(Fexpand_file_name): Tighten the scope of `p' and `o' vars.
Relocate `nm' after calling DECODE_FILE, in case the GC was run.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Sat, 12 Apr 2008 05:12:18 +0000 |
parents | 61a7d458829c |
children | a66451222c6a |
comparison
equal
deleted
inserted
replaced
94036:d669760bc2f0 | 94037:d864a5e618e0 |
---|---|
1040 An initial `~USER/' expands to USER's home directory. | 1040 An initial `~USER/' expands to USER's home directory. |
1041 See also the function `substitute-in-file-name'. */) | 1041 See also the function `substitute-in-file-name'. */) |
1042 (name, default_directory) | 1042 (name, default_directory) |
1043 Lisp_Object name, default_directory; | 1043 Lisp_Object name, default_directory; |
1044 { | 1044 { |
1045 unsigned char *nm; | 1045 /* These point to SDATA and need to be careful with string-relocation |
1046 | 1046 during GC (via DECODE_FILE). */ |
1047 register unsigned char *newdir, *p, *o; | 1047 unsigned char *nm, *newdir; |
1048 /* This should only point to alloca'd data. */ | |
1049 unsigned char *target; | |
1050 | |
1048 int tlen; | 1051 int tlen; |
1049 unsigned char *target; | |
1050 struct passwd *pw; | 1052 struct passwd *pw; |
1051 #ifdef VMS | 1053 #ifdef VMS |
1052 unsigned char * colon = 0; | 1054 unsigned char * colon = 0; |
1053 unsigned char * close = 0; | 1055 unsigned char * close = 0; |
1054 unsigned char * slash = 0; | 1056 unsigned char * slash = 0; |
1101 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name); | 1103 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name); |
1102 if (!NILP (handler)) | 1104 if (!NILP (handler)) |
1103 return call3 (handler, Qexpand_file_name, name, default_directory); | 1105 return call3 (handler, Qexpand_file_name, name, default_directory); |
1104 } | 1106 } |
1105 | 1107 |
1106 o = SDATA (default_directory); | 1108 { |
1107 | 1109 unsigned char *o = SDATA (default_directory); |
1108 /* Make sure DEFAULT_DIRECTORY is properly expanded. | 1110 |
1109 It would be better to do this down below where we actually use | 1111 /* Make sure DEFAULT_DIRECTORY is properly expanded. |
1110 default_directory. Unfortunately, calling Fexpand_file_name recursively | 1112 It would be better to do this down below where we actually use |
1111 could invoke GC, and the strings might be relocated. This would | 1113 default_directory. Unfortunately, calling Fexpand_file_name recursively |
1112 be annoying because we have pointers into strings lying around | 1114 could invoke GC, and the strings might be relocated. This would |
1113 that would need adjusting, and people would add new pointers to | 1115 be annoying because we have pointers into strings lying around |
1114 the code and forget to adjust them, resulting in intermittent bugs. | 1116 that would need adjusting, and people would add new pointers to |
1115 Putting this call here avoids all that crud. | 1117 the code and forget to adjust them, resulting in intermittent bugs. |
1116 | 1118 Putting this call here avoids all that crud. |
1117 The EQ test avoids infinite recursion. */ | 1119 |
1118 if (! NILP (default_directory) && !EQ (default_directory, name) | 1120 The EQ test avoids infinite recursion. */ |
1119 /* Save time in some common cases - as long as default_directory | 1121 if (! NILP (default_directory) && !EQ (default_directory, name) |
1120 is not relative, it can be canonicalized with name below (if it | 1122 /* Save time in some common cases - as long as default_directory |
1121 is needed at all) without requiring it to be expanded now. */ | 1123 is not relative, it can be canonicalized with name below (if it |
1124 is needed at all) without requiring it to be expanded now. */ | |
1122 #ifdef DOS_NT | 1125 #ifdef DOS_NT |
1123 /* Detect MSDOS file names with drive specifiers. */ | 1126 /* Detect MSDOS file names with drive specifiers. */ |
1124 && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])) | 1127 && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) |
1128 && IS_DIRECTORY_SEP (o[2])) | |
1125 #ifdef WINDOWSNT | 1129 #ifdef WINDOWSNT |
1126 /* Detect Windows file names in UNC format. */ | 1130 /* Detect Windows file names in UNC format. */ |
1127 && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) | 1131 && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) |
1128 #endif | 1132 #endif |
1129 #else /* not DOS_NT */ | 1133 #else /* not DOS_NT */ |
1130 /* Detect Unix absolute file names (/... alone is not absolute on | 1134 /* Detect Unix absolute file names (/... alone is not absolute on |
1131 DOS or Windows). */ | 1135 DOS or Windows). */ |
1132 && ! (IS_DIRECTORY_SEP (o[0])) | 1136 && ! (IS_DIRECTORY_SEP (o[0])) |
1133 #endif /* not DOS_NT */ | 1137 #endif /* not DOS_NT */ |
1134 ) | 1138 ) |
1135 { | 1139 { |
1136 struct gcpro gcpro1; | 1140 struct gcpro gcpro1; |
1137 | 1141 |
1138 GCPRO1 (name); | 1142 GCPRO1 (name); |
1139 default_directory = Fexpand_file_name (default_directory, Qnil); | 1143 default_directory = Fexpand_file_name (default_directory, Qnil); |
1140 UNGCPRO; | 1144 UNGCPRO; |
1141 } | 1145 } |
1142 | 1146 } |
1143 name = FILE_SYSTEM_CASE (name); | 1147 name = FILE_SYSTEM_CASE (name); |
1144 multibyte = STRING_MULTIBYTE (name); | 1148 multibyte = STRING_MULTIBYTE (name); |
1145 if (multibyte != STRING_MULTIBYTE (default_directory)) | 1149 if (multibyte != STRING_MULTIBYTE (default_directory)) |
1146 { | 1150 { |
1147 if (multibyte) | 1151 if (multibyte) |
1180 /* If we see "c://somedir", we want to strip the first slash after the | 1184 /* If we see "c://somedir", we want to strip the first slash after the |
1181 colon when stripping the drive letter. Otherwise, this expands to | 1185 colon when stripping the drive letter. Otherwise, this expands to |
1182 "//somedir". */ | 1186 "//somedir". */ |
1183 if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | 1187 if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) |
1184 nm++; | 1188 nm++; |
1189 | |
1190 /* Discard any previous drive specifier if nm is now in UNC format. */ | |
1191 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | |
1192 { | |
1193 drive = 0; | |
1194 } | |
1185 #endif /* WINDOWSNT */ | 1195 #endif /* WINDOWSNT */ |
1186 #endif /* DOS_NT */ | 1196 #endif /* DOS_NT */ |
1187 | |
1188 #ifdef WINDOWSNT | |
1189 /* Discard any previous drive specifier if nm is now in UNC format. */ | |
1190 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | |
1191 { | |
1192 drive = 0; | |
1193 } | |
1194 #endif | |
1195 | 1197 |
1196 /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if | 1198 /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if |
1197 none are found, we can probably return right away. We will avoid | 1199 none are found, we can probably return right away. We will avoid |
1198 allocating a new string if name is already fully expanded. */ | 1200 allocating a new string if name is already fully expanded. */ |
1199 if ( | 1201 if ( |
1214 things; we just need to construct a new string using data | 1216 things; we just need to construct a new string using data |
1215 starting at the middle of FILENAME. If we set lose to a | 1217 starting at the middle of FILENAME. If we set lose to a |
1216 non-zero value, that means we've discovered that we can't do | 1218 non-zero value, that means we've discovered that we can't do |
1217 that cool trick. */ | 1219 that cool trick. */ |
1218 int lose = 0; | 1220 int lose = 0; |
1219 | 1221 unsigned char *p = nm; |
1220 p = nm; | 1222 |
1221 while (*p) | 1223 while (*p) |
1222 { | 1224 { |
1223 /* Since we know the name is absolute, we can assume that each | 1225 /* Since we know the name is absolute, we can assume that each |
1224 element starts with a "/". */ | 1226 element starts with a "/". */ |
1225 | 1227 |
1387 /* egetenv may return a unibyte string, which will bite us since | 1389 /* egetenv may return a unibyte string, which will bite us since |
1388 we expect the directory to be multibyte. */ | 1390 we expect the directory to be multibyte. */ |
1389 tem = build_string (newdir); | 1391 tem = build_string (newdir); |
1390 if (!STRING_MULTIBYTE (tem)) | 1392 if (!STRING_MULTIBYTE (tem)) |
1391 { | 1393 { |
1394 /* FIXME: DECODE_FILE may GC, which may move SDATA(name), | |
1395 after which `nm' won't point to the right place any more. */ | |
1396 int offset = nm - SDATA (name); | |
1392 hdir = DECODE_FILE (tem); | 1397 hdir = DECODE_FILE (tem); |
1393 newdir = SDATA (hdir); | 1398 newdir = SDATA (hdir); |
1399 nm = SDATA (name) + offset; | |
1394 } | 1400 } |
1395 #ifdef DOS_NT | 1401 #ifdef DOS_NT |
1396 collapse_newdir = 0; | 1402 collapse_newdir = 0; |
1397 #endif | 1403 #endif |
1398 #ifdef VMS | 1404 #ifdef VMS |
1399 nm++; /* Don't leave the slash in nm. */ | 1405 nm++; /* Don't leave the slash in nm. */ |
1400 #endif /* VMS */ | 1406 #endif /* VMS */ |
1401 } | 1407 } |
1402 else /* ~user/filename */ | 1408 else /* ~user/filename */ |
1403 { | 1409 { |
1410 unsigned char *o, *p; | |
1404 for (p = nm; *p && (!IS_DIRECTORY_SEP (*p) | 1411 for (p = nm; *p && (!IS_DIRECTORY_SEP (*p) |
1405 #ifdef VMS | 1412 #ifdef VMS |
1406 && *p != ':' | 1413 && *p != ':' |
1407 #endif /* VMS */ | 1414 #endif /* VMS */ |
1408 ); p++); | 1415 ); p++); |
1409 o = (unsigned char *) alloca (p - nm + 1); | 1416 o = alloca (p - nm + 1); |
1410 bcopy ((char *) nm, o, p - nm); | 1417 bcopy ((char *) nm, o, p - nm); |
1411 o [p - nm] = 0; | 1418 o [p - nm] = 0; |
1412 | 1419 |
1413 BLOCK_INPUT; | 1420 BLOCK_INPUT; |
1414 pw = (struct passwd *) getpwnam (o + 1); | 1421 pw = (struct passwd *) getpwnam (o + 1); |
1616 /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */ | 1623 /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */ |
1617 | 1624 |
1618 /* Now canonicalize by removing `//', `/.' and `/foo/..' if they | 1625 /* Now canonicalize by removing `//', `/.' and `/foo/..' if they |
1619 appear. */ | 1626 appear. */ |
1620 | 1627 |
1621 p = target; | 1628 { |
1622 o = target; | 1629 unsigned char *p = target; |
1623 | 1630 unsigned char *o = target; |
1624 while (*p) | 1631 |
1625 { | 1632 while (*p) |
1633 { | |
1626 #ifdef VMS | 1634 #ifdef VMS |
1627 if (*p != ']' && *p != '>' && *p != '-') | 1635 if (*p != ']' && *p != '>' && *p != '-') |
1628 { | 1636 { |
1629 if (*p == '\\') | 1637 if (*p == '\\') |
1630 p++; | 1638 p++; |
1631 *o++ = *p++; | 1639 *o++ = *p++; |
1632 } | 1640 } |
1633 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) | 1641 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) |
1634 /* brackets are offset from each other by 2 */ | 1642 /* brackets are offset from each other by 2 */ |
1635 { | 1643 { |
1636 p += 2; | 1644 p += 2; |
1637 if (*p != '.' && *p != '-' && o[-1] != '.') | 1645 if (*p != '.' && *p != '-' && o[-1] != '.') |
1638 /* convert [foo][bar] to [bar] */ | 1646 /* convert [foo][bar] to [bar] */ |
1639 while (o[-1] != '[' && o[-1] != '<') | 1647 while (o[-1] != '[' && o[-1] != '<') |
1648 o--; | |
1649 else if (*p == '-' && *o != '.') | |
1650 *--p = '.'; | |
1651 } | |
1652 else if (p[0] == '-' && o[-1] == '.' | |
1653 && (p[1] == '.' || p[1] == ']' || p[1] == '>')) | |
1654 /* flush .foo.- ; leave - if stopped by '[' or '<' */ | |
1655 { | |
1656 do | |
1640 o--; | 1657 o--; |
1641 else if (*p == '-' && *o != '.') | 1658 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); |
1642 *--p = '.'; | 1659 if (p[1] == '.') /* foo.-.bar ==> bar. */ |
1643 } | 1660 p += 2; |
1644 else if (p[0] == '-' && o[-1] == '.' | 1661 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ |
1645 && (p[1] == '.' || p[1] == ']' || p[1] == '>')) | 1662 p++, o--; |
1646 /* flush .foo.- ; leave - if stopped by '[' or '<' */ | 1663 /* else [foo.-] ==> [-] */ |
1647 { | 1664 } |
1648 do | 1665 else |
1649 o--; | 1666 { |
1650 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); | 1667 #ifdef NO_HYPHENS_IN_FILENAMES |
1651 if (p[1] == '.') /* foo.-.bar ==> bar. */ | 1668 if (*p == '-' |
1669 && o[-1] != '[' && o[-1] != '<' && o[-1] != '.' | |
1670 && p[1] != ']' && p[1] != '>' && p[1] != '.') | |
1671 *p = '_'; | |
1672 #endif /* NO_HYPHENS_IN_FILENAMES */ | |
1673 *o++ = *p++; | |
1674 } | |
1675 #else /* not VMS */ | |
1676 if (!IS_DIRECTORY_SEP (*p)) | |
1677 { | |
1678 *o++ = *p++; | |
1679 } | |
1680 else if (p[1] == '.' | |
1681 && (IS_DIRECTORY_SEP (p[2]) | |
1682 || p[2] == 0)) | |
1683 { | |
1684 /* If "/." is the entire filename, keep the "/". Otherwise, | |
1685 just delete the whole "/.". */ | |
1686 if (o == target && p[2] == '\0') | |
1687 *o++ = *p; | |
1652 p += 2; | 1688 p += 2; |
1653 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ | 1689 } |
1654 p++, o--; | 1690 else if (p[1] == '.' && p[2] == '.' |
1655 /* else [foo.-] ==> [-] */ | 1691 /* `/../' is the "superroot" on certain file systems. |
1656 } | 1692 Turned off on DOS_NT systems because they have no |
1657 else | 1693 "superroot" and because this causes us to produce |
1658 { | 1694 file names like "d:/../foo" which fail file-related |
1659 #ifdef NO_HYPHENS_IN_FILENAMES | 1695 functions of the underlying OS. (To reproduce, try a |
1660 if (*p == '-' | 1696 long series of "../../" in default_directory, longer |
1661 && o[-1] != '[' && o[-1] != '<' && o[-1] != '.' | 1697 than the number of levels from the root.) */ |
1662 && p[1] != ']' && p[1] != '>' && p[1] != '.') | |
1663 *p = '_'; | |
1664 #endif /* NO_HYPHENS_IN_FILENAMES */ | |
1665 *o++ = *p++; | |
1666 } | |
1667 #else /* not VMS */ | |
1668 if (!IS_DIRECTORY_SEP (*p)) | |
1669 { | |
1670 *o++ = *p++; | |
1671 } | |
1672 else if (p[1] == '.' | |
1673 && (IS_DIRECTORY_SEP (p[2]) | |
1674 || p[2] == 0)) | |
1675 { | |
1676 /* If "/." is the entire filename, keep the "/". Otherwise, | |
1677 just delete the whole "/.". */ | |
1678 if (o == target && p[2] == '\0') | |
1679 *o++ = *p; | |
1680 p += 2; | |
1681 } | |
1682 else if (p[1] == '.' && p[2] == '.' | |
1683 /* `/../' is the "superroot" on certain file systems. | |
1684 Turned off on DOS_NT systems because they have no | |
1685 "superroot" and because this causes us to produce | |
1686 file names like "d:/../foo" which fail file-related | |
1687 functions of the underlying OS. (To reproduce, try a | |
1688 long series of "../../" in default_directory, longer | |
1689 than the number of levels from the root.) */ | |
1690 #ifndef DOS_NT | 1698 #ifndef DOS_NT |
1691 && o != target | 1699 && o != target |
1692 #endif | 1700 #endif |
1693 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) | 1701 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) |
1694 { | 1702 { |
1695 while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) | 1703 while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) |
1696 ; | 1704 ; |
1697 /* Keep initial / only if this is the whole name. */ | 1705 /* Keep initial / only if this is the whole name. */ |
1698 if (o == target && IS_ANY_SEP (*o) && p[3] == 0) | 1706 if (o == target && IS_ANY_SEP (*o) && p[3] == 0) |
1699 ++o; | 1707 ++o; |
1700 p += 3; | 1708 p += 3; |
1701 } | 1709 } |
1702 else if (p > target && IS_DIRECTORY_SEP (p[1])) | 1710 else if (p > target && IS_DIRECTORY_SEP (p[1])) |
1703 /* Collapse multiple `/' in a row. */ | 1711 /* Collapse multiple `/' in a row. */ |
1704 p++; | 1712 p++; |
1705 else | 1713 else |
1706 { | 1714 { |
1707 *o++ = *p++; | 1715 *o++ = *p++; |
1708 } | 1716 } |
1709 #endif /* not VMS */ | 1717 #endif /* not VMS */ |
1710 } | 1718 } |
1711 | 1719 |
1712 #ifdef DOS_NT | 1720 #ifdef DOS_NT |
1713 /* At last, set drive name. */ | 1721 /* At last, set drive name. */ |
1714 #ifdef WINDOWSNT | 1722 #ifdef WINDOWSNT |
1715 /* Except for network file name. */ | 1723 /* Except for network file name. */ |
1716 if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))) | 1724 if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))) |
1717 #endif /* WINDOWSNT */ | 1725 #endif /* WINDOWSNT */ |
1718 { | 1726 { |
1719 if (!drive) abort (); | 1727 if (!drive) abort (); |
1720 target -= 2; | 1728 target -= 2; |
1721 target[0] = DRIVE_LETTER (drive); | 1729 target[0] = DRIVE_LETTER (drive); |
1722 target[1] = ':'; | 1730 target[1] = ':'; |
1723 } | 1731 } |
1724 /* Reinsert the escape prefix if required. */ | 1732 /* Reinsert the escape prefix if required. */ |
1725 if (is_escaped) | 1733 if (is_escaped) |
1726 { | 1734 { |
1727 target -= 2; | 1735 target -= 2; |
1728 target[0] = '/'; | 1736 target[0] = '/'; |
1729 target[1] = ':'; | 1737 target[1] = ':'; |
1730 } | 1738 } |
1731 CORRECT_DIR_SEPS (target); | 1739 CORRECT_DIR_SEPS (target); |
1732 #endif /* DOS_NT */ | 1740 #endif /* DOS_NT */ |
1733 | 1741 |
1734 result = make_specified_string (target, -1, o - target, multibyte); | 1742 result = make_specified_string (target, -1, o - target, multibyte); |
1743 } | |
1735 | 1744 |
1736 /* Again look to see if the file name has special constructs in it | 1745 /* Again look to see if the file name has special constructs in it |
1737 and perhaps call the corresponding file handler. This is needed | 1746 and perhaps call the corresponding file handler. This is needed |
1738 for filenames such as "/foo/../user@host:/bar/../baz". Expanding | 1747 for filenames such as "/foo/../user@host:/bar/../baz". Expanding |
1739 the ".." component gives us "/user@host:/bar/../baz" which needs | 1748 the ".." component gives us "/user@host:/bar/../baz" which needs |