diff options
Diffstat (limited to 'src/w32.c')
| -rw-r--r-- | src/w32.c | 106 |
1 files changed, 95 insertions, 11 deletions
| @@ -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. */ | ||
| 1535 | static 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. */ | ||
| 1540 | static int | ||
| 1541 | max_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 | |||
| 1540 | normalize_filename (register char *fp, char path_sep) | 1601 | normalize_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; |