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