aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c106
1 files changed, 95 insertions, 11 deletions
diff --git a/src/w32.c b/src/w32.c
index d014609076e..f722bc5f397 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -37,7 +37,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
37/* must include CRT headers *before* config.h */ 37/* must include CRT headers *before* config.h */
38 38
39#include <config.h> 39#include <config.h>
40#include <mbstring.h> /* for _mbspbrk */ 40#include <mbstring.h> /* for _mbspbrk and _mbslwr */
41 41
42#undef access 42#undef access
43#undef chdir 43#undef chdir
@@ -1531,6 +1531,67 @@ srandom (int seed)
1531 srand (seed); 1531 srand (seed);
1532} 1532}
1533 1533
1534/* Current codepage for encoding file names. */
1535static int file_name_codepage;
1536
1537/* Return the maximum length in bytes of a multibyte character
1538 sequence encoded in the current ANSI codepage. This is required to
1539 correctly walk the encoded file names one character at a time. */
1540static int
1541max_filename_mbslen (void)
1542{
1543 /* A simple cache to avoid calling GetCPInfo every time we need to
1544 normalize a file name. The file-name encoding is not supposed to
1545 be changed too frequently, if ever. */
1546 static Lisp_Object last_file_name_encoding;
1547 static int last_max_mbslen;
1548 Lisp_Object current_encoding;
1549
1550 current_encoding = Vfile_name_coding_system;
1551 if (NILP (current_encoding))
1552 current_encoding = Vdefault_file_name_coding_system;
1553
1554 if (!EQ (last_file_name_encoding, current_encoding))
1555 {
1556 CPINFO cp_info;
1557
1558 last_file_name_encoding = current_encoding;
1559 /* Default to the current ANSI codepage. */
1560 file_name_codepage = w32_ansi_code_page;
1561 if (!NILP (current_encoding))
1562 {
1563 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1564 char *cp = NULL, *end;
1565 int cpnum;
1566
1567 if (strncmp (cpname, "cp", 2) == 0)
1568 cp = cpname + 2;
1569 else if (strncmp (cpname, "windows-", 8) == 0)
1570 cp = cpname + 8;
1571
1572 if (cp)
1573 {
1574 end = cp;
1575 cpnum = strtol (cp, &end, 10);
1576 if (cpnum && *end == '\0' && end - cp >= 2)
1577 file_name_codepage = cpnum;
1578 }
1579 }
1580
1581 if (!file_name_codepage)
1582 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1583
1584 if (!GetCPInfo (file_name_codepage, &cp_info))
1585 {
1586 file_name_codepage = CP_ACP;
1587 if (!GetCPInfo (file_name_codepage, &cp_info))
1588 emacs_abort ();
1589 }
1590 last_max_mbslen = cp_info.MaxCharSize;
1591 }
1592
1593 return last_max_mbslen;
1594}
1534 1595
1535/* Normalize filename by converting all path separators to 1596/* Normalize filename by converting all path separators to
1536 the specified separator. Also conditionally convert upper 1597 the specified separator. Also conditionally convert upper
@@ -1540,14 +1601,20 @@ static void
1540normalize_filename (register char *fp, char path_sep) 1601normalize_filename (register char *fp, char path_sep)
1541{ 1602{
1542 char sep; 1603 char sep;
1543 char *elem; 1604 char *elem, *p2;
1605 int dbcs_p = max_filename_mbslen () > 1;
1544 1606
1545 /* Always lower-case drive letters a-z, even if the filesystem 1607 /* Always lower-case drive letters a-z, even if the filesystem
1546 preserves case in filenames. 1608 preserves case in filenames.
1547 This is so filenames can be compared by string comparison 1609 This is so filenames can be compared by string comparison
1548 functions that are case-sensitive. Even case-preserving filesystems 1610 functions that are case-sensitive. Even case-preserving filesystems
1549 do not distinguish case in drive letters. */ 1611 do not distinguish case in drive letters. */
1550 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') 1612 if (dbcs_p)
1613 p2 = CharNextExA (file_name_codepage, fp, 0);
1614 else
1615 p2 = fp + 1;
1616
1617 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1551 { 1618 {
1552 *fp += 'a' - 'A'; 1619 *fp += 'a' - 'A';
1553 fp += 2; 1620 fp += 2;
@@ -1559,7 +1626,10 @@ normalize_filename (register char *fp, char path_sep)
1559 { 1626 {
1560 if (*fp == '/' || *fp == '\\') 1627 if (*fp == '/' || *fp == '\\')
1561 *fp = path_sep; 1628 *fp = path_sep;
1562 fp++; 1629 if (!dbcs_p)
1630 fp++;
1631 else
1632 fp = CharNextExA (file_name_codepage, fp, 0);
1563 } 1633 }
1564 return; 1634 return;
1565 } 1635 }
@@ -1582,13 +1652,20 @@ normalize_filename (register char *fp, char path_sep)
1582 if (elem && elem != fp) 1652 if (elem && elem != fp)
1583 { 1653 {
1584 *fp = 0; /* temporary end of string */ 1654 *fp = 0; /* temporary end of string */
1585 _strlwr (elem); /* while we convert to lower case */ 1655 _mbslwr (elem); /* while we convert to lower case */
1586 } 1656 }
1587 *fp = sep; /* convert (or restore) path separator */ 1657 *fp = sep; /* convert (or restore) path separator */
1588 elem = fp + 1; /* next element starts after separator */ 1658 elem = fp + 1; /* next element starts after separator */
1589 sep = path_sep; 1659 sep = path_sep;
1590 } 1660 }
1591 } while (*fp++); 1661 if (*fp)
1662 {
1663 if (!dbcs_p)
1664 fp++;
1665 else
1666 fp = CharNextExA (file_name_codepage, fp, 0);
1667 }
1668 } while (*fp);
1592} 1669}
1593 1670
1594/* Destructively turn backslashes into slashes. */ 1671/* Destructively turn backslashes into slashes. */
@@ -2860,15 +2937,22 @@ readdir (DIR *dirp)
2860 strcpy (dir_static.d_name, dir_find_data.cFileName); 2937 strcpy (dir_static.d_name, dir_find_data.cFileName);
2861 dir_static.d_namlen = strlen (dir_static.d_name); 2938 dir_static.d_namlen = strlen (dir_static.d_name);
2862 if (dir_is_fat) 2939 if (dir_is_fat)
2863 _strlwr (dir_static.d_name); 2940 _mbslwr (dir_static.d_name);
2864 else if (downcase) 2941 else if (downcase)
2865 { 2942 {
2866 register char *p; 2943 register char *p;
2867 for (p = dir_static.d_name; *p; p++) 2944 int dbcs_p = max_filename_mbslen () > 1;
2868 if (*p >= 'a' && *p <= 'z') 2945 for (p = dir_static.d_name; *p; )
2869 break; 2946 {
2947 if (*p >= 'a' && *p <= 'z')
2948 break;
2949 if (dbcs_p)
2950 p = CharNextExA (file_name_codepage, p, 0);
2951 else
2952 p++;
2953 }
2870 if (!*p) 2954 if (!*p)
2871 _strlwr (dir_static.d_name); 2955 _mbslwr (dir_static.d_name);
2872 } 2956 }
2873 2957
2874 return &dir_static; 2958 return &dir_static;