aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog5
-rw-r--r--src/fileio.c283
2 files changed, 151 insertions, 137 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 2081beb13ec..75be9df4b12 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
12008-04-12 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * fileio.c (Fexpand_file_name): Tighten the scope of `p' and `o' vars.
4 Relocate `nm' after calling DECODE_FILE, in case the GC was run.
5
12008-04-11 Stefan Monnier <monnier@iro.umontreal.ca> 62008-04-11 Stefan Monnier <monnier@iro.umontreal.ca>
2 7
3 * keymap.h (map_keymap_canonical): Declare. 8 * keymap.h (map_keymap_canonical): Declare.
diff --git a/src/fileio.c b/src/fileio.c
index f9f37404b1a..26b2ebdeee5 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1042,11 +1042,13 @@ 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 during GC (via DECODE_FILE). */
1047 unsigned char *nm, *newdir;
1048 /* This should only point to alloca'd data. */
1049 unsigned char *target;
1046 1050
1047 register unsigned char *newdir, *p, *o;
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;
@@ -1103,43 +1105,45 @@ See also the function `substitute-in-file-name'. */)
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
1138 GCPRO1 (name);
1139 default_directory = Fexpand_file_name (default_directory, Qnil);
1140 UNGCPRO;
1141 }
1142 1141
1142 GCPRO1 (name);
1143 default_directory = Fexpand_file_name (default_directory, Qnil);
1144 UNGCPRO;
1145 }
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))
@@ -1182,16 +1186,14 @@ See also the function `substitute-in-file-name'. */)
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++;
1185#endif /* WINDOWSNT */
1186#endif /* DOS_NT */
1187 1189
1188#ifdef WINDOWSNT
1189 /* Discard any previous drive specifier if nm is now in UNC format. */ 1190 /* 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 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
1191 { 1192 {
1192 drive = 0; 1193 drive = 0;
1193 } 1194 }
1194#endif 1195#endif /* WINDOWSNT */
1196#endif /* DOS_NT */
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
@@ -1216,8 +1218,8 @@ See also the function `substitute-in-file-name'. */)
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;
1221 unsigned char *p = nm;
1219 1222
1220 p = nm;
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
@@ -1389,8 +1391,12 @@ See also the function `substitute-in-file-name'. */)
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;
@@ -1401,12 +1407,13 @@ See also the function `substitute-in-file-name'. */)
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
@@ -1618,120 +1625,122 @@ See also the function `substitute-in-file-name'. */)
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;
1630 unsigned char *o = target;
1623 1631
1624 while (*p) 1632 while (*p)
1625 { 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;
1637 if (*p != '.' && *p != '-' && o[-1] != '.')
1638 /* convert [foo][bar] to [bar] */
1639 while (o[-1] != '[' && o[-1] != '<')
1640 o--;
1641 else if (*p == '-' && *o != '.')
1642 *--p = '.';
1643 }
1644 else if (p[0] == '-' && o[-1] == '.'
1645 && (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1646 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1647 {
1648 do
1649 o--;
1650 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1651 if (p[1] == '.') /* foo.-.bar ==> bar. */
1652 p += 2; 1644 p += 2;
1653 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ 1645 if (*p != '.' && *p != '-' && o[-1] != '.')
1654 p++, o--; 1646 /* convert [foo][bar] to [bar] */
1655 /* else [foo.-] ==> [-] */ 1647 while (o[-1] != '[' && o[-1] != '<')
1656 } 1648 o--;
1657 else 1649 else if (*p == '-' && *o != '.')
1658 { 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
1657 o--;
1658 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1659 if (p[1] == '.') /* foo.-.bar ==> bar. */
1660 p += 2;
1661 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1662 p++, o--;
1663 /* else [foo.-] ==> [-] */
1664 }
1665 else
1666 {
1659#ifdef NO_HYPHENS_IN_FILENAMES 1667#ifdef NO_HYPHENS_IN_FILENAMES
1660 if (*p == '-' 1668 if (*p == '-'
1661 && o[-1] != '[' && o[-1] != '<' && o[-1] != '.' 1669 && o[-1] != '[' && o[-1] != '<' && o[-1] != '.'
1662 && p[1] != ']' && p[1] != '>' && p[1] != '.') 1670 && p[1] != ']' && p[1] != '>' && p[1] != '.')
1663 *p = '_'; 1671 *p = '_';
1664#endif /* NO_HYPHENS_IN_FILENAMES */ 1672#endif /* NO_HYPHENS_IN_FILENAMES */
1665 *o++ = *p++; 1673 *o++ = *p++;
1666 } 1674 }
1667#else /* not VMS */ 1675#else /* not VMS */
1668 if (!IS_DIRECTORY_SEP (*p)) 1676 if (!IS_DIRECTORY_SEP (*p))
1669 { 1677 {
1670 *o++ = *p++; 1678 *o++ = *p++;
1671 } 1679 }
1672 else if (p[1] == '.' 1680 else if (p[1] == '.'
1673 && (IS_DIRECTORY_SEP (p[2]) 1681 && (IS_DIRECTORY_SEP (p[2])
1674 || p[2] == 0)) 1682 || p[2] == 0))
1675 { 1683 {
1676 /* If "/." is the entire filename, keep the "/". Otherwise, 1684 /* If "/." is the entire filename, keep the "/". Otherwise,
1677 just delete the whole "/.". */ 1685 just delete the whole "/.". */
1678 if (o == target && p[2] == '\0') 1686 if (o == target && p[2] == '\0')
1679 *o++ = *p; 1687 *o++ = *p;
1680 p += 2; 1688 p += 2;
1681 } 1689 }
1682 else if (p[1] == '.' && p[2] == '.' 1690 else if (p[1] == '.' && p[2] == '.'
1683 /* `/../' is the "superroot" on certain file systems. 1691 /* `/../' is the "superroot" on certain file systems.
1684 Turned off on DOS_NT systems because they have no 1692 Turned off on DOS_NT systems because they have no
1685 "superroot" and because this causes us to produce 1693 "superroot" and because this causes us to produce
1686 file names like "d:/../foo" which fail file-related 1694 file names like "d:/../foo" which fail file-related
1687 functions of the underlying OS. (To reproduce, try a 1695 functions of the underlying OS. (To reproduce, try a
1688 long series of "../../" in default_directory, longer 1696 long series of "../../" in default_directory, longer
1689 than the number of levels from the root.) */ 1697 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