Ignore:
Timestamp:
Jan 5, 2002, 8:11:10 PM (24 years ago)
Author:
umoeller
Message:

Tons of updates for turbo folders and replacement icons.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/stringh.c

    r123 r127  
    152152            *ppszTarget = NULL;
    153153    }
     154    else
     155        return (ERROR_INVALID_PARAMETER);
    154156
    155157    if (pulLength)
     
    16591661/* ******************************************************************
    16601662 *
    1661  *   Wildcard matching
    1662  *
    1663  ********************************************************************/
    1664 
    1665 /*
    1666  *  The following code has been taken from "fnmatch.zip".
    1667  *
    1668  *      (c) 1994-1996 by Eberhard Mattes.
    1669  */
    1670 
    1671 /* In OS/2 and DOS styles, both / and \ separate components of a path.
    1672  * This macro returns true iff C is a separator. */
    1673 
    1674 #define IS_OS2_COMP_SEP(C)  ((C) == '/' || (C) == '\\')
    1675 
    1676 
    1677 /* This macro returns true if C is at the end of a component of a
    1678  * path. */
    1679 
    1680 #define IS_OS2_COMP_END(C)  ((C) == 0 || IS_OS2_COMP_SEP (C))
    1681 
    1682 /*
    1683  * skip_comp_os2:
    1684  *      Return a pointer to the next component of the path SRC, for OS/2
    1685  *      and DOS styles.  When the end of the string is reached, a pointer
    1686  *      to the terminating null character is returned.
    1687  *
    1688  *      (c) 1994-1996 by Eberhard Mattes.
    1689  */
    1690 
    1691 static const unsigned char* skip_comp_os2(const unsigned char *src)
    1692 {
    1693     /* Skip characters until hitting a separator or the end of the
    1694      * string. */
    1695 
    1696     while (!IS_OS2_COMP_END(*src))
    1697         ++src;
    1698 
    1699     /* Skip the separator if we hit a separator. */
    1700 
    1701     if (*src != 0)
    1702         ++src;
    1703     return src;
    1704 }
    1705 
    1706 /*
    1707  * has_colon:
    1708  *      returns true iff the path P contains a colon.
    1709  *
    1710  *      (c) 1994-1996 by Eberhard Mattes.
    1711  */
    1712 
    1713 static int has_colon(const unsigned char *p)
    1714 {
    1715     while (*p != 0)
    1716         if (*p == ':')
    1717             return 1;
    1718         else
    1719             ++p;
    1720     return 0;
    1721 }
    1722 
    1723 /*
    1724  * match_comp_os2:
    1725  *      compares a single component (directory name or file name)
    1726  *      of the paths, for OS/2 and DOS styles. MASK and NAME point
    1727  *      into a component of the wildcard and the name to be checked,
    1728  *      respectively. Comparing stops at the next separator.
    1729  *      The FLAGS argument is the same as that of fnmatch().
    1730  *
    1731  *      HAS_DOT is true if a dot is in the current component of NAME.
    1732  *      The number of dots is not restricted, even in DOS style.
    1733  *
    1734  *      Returns FNM_MATCH iff MASK and NAME match.
    1735  *
    1736  *      Note that this function is recursive.
    1737  *
    1738  *      (c) 1994-1996 by Eberhard Mattes.
    1739  */
    1740 
    1741 static int match_comp_os2(const unsigned char *mask,
    1742                           const unsigned char *name,
    1743                           unsigned flags,
    1744                           int has_dot)
    1745 {
    1746     int             rc;
    1747 
    1748     for (;;)
    1749         switch (*mask)
    1750         {
    1751             case 0:
    1752 
    1753                 /* There must be no extra characters at the end of NAME when
    1754                  * reaching the end of MASK unless _FNM_PATHPREFIX is set:
    1755                  * in that case, NAME may point to a separator. */
    1756 
    1757                 if (*name == 0)
    1758                     return FNM_MATCH;
    1759                 if ((flags & FNM_PATHPREFIX) && IS_OS2_COMP_SEP(*name))
    1760                     return FNM_MATCH;
    1761                 return FNM_NOMATCH;
    1762 
    1763             case '/':
    1764             case '\\':
    1765 
    1766                 /* Separators match separators. */
    1767 
    1768                 if (IS_OS2_COMP_SEP(*name))
    1769                     return FNM_MATCH;
    1770 
    1771                 /* If _FNM_PATHPREFIX is set, a trailing separator in MASK
    1772                  * is ignored at the end of NAME. */
    1773 
    1774                 if ((flags & FNM_PATHPREFIX) && mask[1] == 0 && *name == 0)
    1775                     return FNM_MATCH;
    1776 
    1777                 /* Stop comparing at the separator. */
    1778 
    1779                 return FNM_NOMATCH;
    1780 
    1781             case '?':
    1782 
    1783                 /* A question mark matches one character.  It does not match
    1784                  * a dot.  At the end of the component (and before a dot),
    1785                  * it also matches zero characters. */
    1786 
    1787                 if (*name != '.' && !IS_OS2_COMP_END(*name))
    1788                     ++name;
    1789                 ++mask;
    1790                 break;
    1791 
    1792             case '*':
    1793 
    1794                 /* An asterisk matches zero or more characters.  In DOS
    1795                  * mode, dots are not matched. */
    1796 
    1797                 do
    1798                 {
    1799                     ++mask;
    1800                 }
    1801                 while (*mask == '*');
    1802                 for (;;)
    1803                 {
    1804                     rc = match_comp_os2(mask, name, flags, has_dot);
    1805                     if (rc != FNM_NOMATCH)
    1806                         return rc;
    1807                     if (IS_OS2_COMP_END(*name))
    1808                         return FNM_NOMATCH;
    1809                     if (*name == '.' && (flags & FNM_STYLE_MASK) == FNM_DOS)
    1810                         return FNM_NOMATCH;
    1811                     ++name;
    1812                 }
    1813 
    1814             case '.':
    1815 
    1816                 /* A dot matches a dot.  It also matches the implicit dot at
    1817                  * the end of a dot-less NAME. */
    1818 
    1819                 ++mask;
    1820                 if (*name == '.')
    1821                     ++name;
    1822                 else if (has_dot || !IS_OS2_COMP_END(*name))
    1823                     return FNM_NOMATCH;
    1824                 break;
    1825 
    1826             default:
    1827 
    1828                 /* All other characters match themselves. */
    1829 
    1830                 if (flags & FNM_IGNORECASE)
    1831                 {
    1832                     if (tolower(*mask) != tolower(*name))
    1833                         return FNM_NOMATCH;
    1834                 }
    1835                 else
    1836                 {
    1837                     if (*mask != *name)
    1838                         return FNM_NOMATCH;
    1839                 }
    1840                 ++mask;
    1841                 ++name;
    1842                 break;
    1843         }
    1844 }
    1845 
    1846 /*
    1847  * match_comp:
    1848  *      compares a single component (directory name or file
    1849  *      name) of the paths, for all styles which need
    1850  *      component-by-component matching. MASK and NAME point
    1851  *      to the start of a component of the wildcard and the
    1852  *      name to be checked, respectively.  Comparing stops at
    1853  *      the next separator. The FLAGS argument is the same as
    1854  *      that of fnmatch().
    1855  *
    1856  *      Return FNM_MATCH iff MASK and NAME match.
    1857  *
    1858  *      (c) 1994-1996 by Eberhard Mattes.
    1859  */
    1860 
    1861 static int match_comp(const unsigned char *mask,
    1862                       const unsigned char *name,
    1863                       unsigned flags)
    1864 {
    1865     const unsigned char *s;
    1866 
    1867     switch (flags & FNM_STYLE_MASK)
    1868     {
    1869         case FNM_OS2:
    1870         case FNM_DOS:
    1871 
    1872             /* For OS/2 and DOS styles, we add an implicit dot at the end of
    1873              * the component if the component doesn't include a dot. */
    1874 
    1875             s = name;
    1876             while (!IS_OS2_COMP_END(*s) && *s != '.')
    1877                 ++s;
    1878             return match_comp_os2(mask, name, flags, *s == '.');
    1879 
    1880         default:
    1881             return FNM_ERR;
    1882     }
    1883 }
    1884 
    1885 /* In Unix styles, / separates components of a path.  This macro
    1886  * returns true iff C is a separator. */
    1887 
    1888 #define IS_UNIX_COMP_SEP(C)  ((C) == '/')
    1889 
    1890 
    1891 /* This macro returns true if C is at the end of a component of a
    1892  * path. */
    1893 
    1894 #define IS_UNIX_COMP_END(C)  ((C) == 0 || IS_UNIX_COMP_SEP (C))
    1895 
    1896 /*
    1897  * match_unix:
    1898  *      matches complete paths for Unix styles.
    1899  *
    1900  *      The FLAGS argument is the same as that of fnmatch().
    1901  *      COMP points to the start of the current component in
    1902  *      NAME.  Return FNM_MATCH iff MASK and NAME match.  The
    1903  *      backslash character is used for escaping ? and * unless
    1904  *      FNM_NOESCAPE is set.
    1905  *
    1906  *      (c) 1994-1996 by Eberhard Mattes.
    1907  */
    1908 
    1909 static int match_unix(const unsigned char *mask,
    1910                       const unsigned char *name,
    1911                       unsigned flags,
    1912                       const unsigned char *comp)
    1913 {
    1914     unsigned char   c1, c2;
    1915     char            invert, matched;
    1916     const unsigned char *start;
    1917     int             rc;
    1918 
    1919     for (;;)
    1920         switch (*mask)
    1921         {
    1922             case 0:
    1923 
    1924                 /* There must be no extra characters at the end of NAME when
    1925                  * reaching the end of MASK unless _FNM_PATHPREFIX is set:
    1926                  * in that case, NAME may point to a separator. */
    1927 
    1928                 if (*name == 0)
    1929                     return FNM_MATCH;
    1930                 if ((flags & FNM_PATHPREFIX) && IS_UNIX_COMP_SEP(*name))
    1931                     return FNM_MATCH;
    1932                 return FNM_NOMATCH;
    1933 
    1934             case '?':
    1935 
    1936                 /* A question mark matches one character.  It does not match
    1937                  * the component separator if FNM_PATHNAME is set.  It does
    1938                  * not match a dot at the start of a component if FNM_PERIOD
    1939                  * is set. */
    1940 
    1941                 if (*name == 0)
    1942                     return FNM_NOMATCH;
    1943                 if ((flags & FNM_PATHNAME) && IS_UNIX_COMP_SEP(*name))
    1944                     return FNM_NOMATCH;
    1945                 if (*name == '.' && (flags & FNM_PERIOD) && name == comp)
    1946                     return FNM_NOMATCH;
    1947                 ++mask;
    1948                 ++name;
    1949                 break;
    1950 
    1951             case '*':
    1952 
    1953                 /* An asterisk matches zero or more characters.  It does not
    1954                  * match the component separator if FNM_PATHNAME is set.  It
    1955                  * does not match a dot at the start of a component if
    1956                  * FNM_PERIOD is set. */
    1957 
    1958                 if (*name == '.' && (flags & FNM_PERIOD) && name == comp)
    1959                     return FNM_NOMATCH;
    1960                 do
    1961                 {
    1962                     ++mask;
    1963                 }
    1964                 while (*mask == '*');
    1965                 for (;;)
    1966                 {
    1967                     rc = match_unix(mask, name, flags, comp);
    1968                     if (rc != FNM_NOMATCH)
    1969                         return rc;
    1970                     if (*name == 0)
    1971                         return FNM_NOMATCH;
    1972                     if ((flags & FNM_PATHNAME) && IS_UNIX_COMP_SEP(*name))
    1973                         return FNM_NOMATCH;
    1974                     ++name;
    1975                 }
    1976 
    1977             case '/':
    1978 
    1979                 /* Separators match only separators.  If _FNM_PATHPREFIX is
    1980                  * set, a trailing separator in MASK is ignored at the end
    1981                  * of NAME. */
    1982 
    1983                 if (!(IS_UNIX_COMP_SEP(*name)
    1984                       || ((flags & FNM_PATHPREFIX) && *name == 0
    1985                       && (mask[1] == 0
    1986                           || (!(flags & FNM_NOESCAPE) && mask[1] == '\\'
    1987                   && mask[2] == 0)))))
    1988                     return FNM_NOMATCH;
    1989 
    1990                 ++mask;
    1991                 if (*name != 0)
    1992                     ++name;
    1993 
    1994                 /* This is the beginning of a new component if FNM_PATHNAME
    1995                  * is set. */
    1996 
    1997                 if (flags & FNM_PATHNAME)
    1998                     comp = name;
    1999                 break;
    2000 
    2001             case '[':
    2002 
    2003                 /* A set of characters.  Always case-sensitive. */
    2004 
    2005                 if (*name == 0)
    2006                     return FNM_NOMATCH;
    2007                 if ((flags & FNM_PATHNAME) && IS_UNIX_COMP_SEP(*name))
    2008                     return FNM_NOMATCH;
    2009                 if (*name == '.' && (flags & FNM_PERIOD) && name == comp)
    2010                     return FNM_NOMATCH;
    2011 
    2012                 invert = 0;
    2013                 matched = 0;
    2014                 ++mask;
    2015 
    2016                 /* If the first character is a ! or ^, the set matches all
    2017                  * characters not listed in the set. */
    2018 
    2019                 if (*mask == '!' || *mask == '^')
    2020                 {
    2021                     ++mask;
    2022                     invert = 1;
    2023                 }
    2024 
    2025                 /* Loop over all the characters of the set.  The loop ends
    2026                  * if the end of the string is reached or if a ] is
    2027                  * encountered unless it directly follows the initial [ or
    2028                  * [-. */
    2029 
    2030                 start = mask;
    2031                 while (!(*mask == 0 || (*mask == ']' && mask != start)))
    2032                 {
    2033                     /* Get the next character which is optionally preceded
    2034                      * by a backslash. */
    2035 
    2036                     c1 = *mask++;
    2037                     if (!(flags & FNM_NOESCAPE) && c1 == '\\')
    2038                     {
    2039                         if (*mask == 0)
    2040                             break;
    2041                         c1 = *mask++;
    2042                     }
    2043 
    2044                     /* Ranges of characters are written as a-z.  Don't
    2045                      * forget to check for the end of the string and to
    2046                      * handle the backslash.  If the character after - is a
    2047                      * ], it isn't a range. */
    2048 
    2049                     if (*mask == '-' && mask[1] != ']')
    2050                     {
    2051                         ++mask; /* Skip the - character */
    2052                         if (!(flags & FNM_NOESCAPE) && *mask == '\\')
    2053                             ++mask;
    2054                         if (*mask == 0)
    2055                             break;
    2056                         c2 = *mask++;
    2057                     }
    2058                     else
    2059                         c2 = c1;
    2060 
    2061                     /* Now check whether this character or range matches NAME. */
    2062 
    2063                     if (c1 <= *name && *name <= c2)
    2064                         matched = 1;
    2065                 }
    2066 
    2067                 /* If the end of the string is reached before a ] is found,
    2068                  * back up to the [ and compare it to NAME. */
    2069 
    2070                 if (*mask == 0)
    2071                 {
    2072                     if (*name != '[')
    2073                         return FNM_NOMATCH;
    2074                     ++name;
    2075                     mask = start;
    2076                     if (invert)
    2077                         --mask;
    2078                 }
    2079                 else
    2080                 {
    2081                     if (invert)
    2082                         matched = !matched;
    2083                     if (!matched)
    2084                         return FNM_NOMATCH;
    2085                     ++mask;     /* Skip the ] character */
    2086                     if (*name != 0)
    2087                         ++name;
    2088                 }
    2089                 break;
    2090 
    2091             case '\\':
    2092                 ++mask;
    2093                 if (flags & FNM_NOESCAPE)
    2094                 {
    2095                     if (*name != '\\')
    2096                         return FNM_NOMATCH;
    2097                     ++name;
    2098                 }
    2099                 else if (*mask == '*' || *mask == '?')
    2100                 {
    2101                     if (*mask != *name)
    2102                         return FNM_NOMATCH;
    2103                     ++mask;
    2104                     ++name;
    2105                 }
    2106                 break;
    2107 
    2108             default:
    2109 
    2110                 /* All other characters match themselves. */
    2111 
    2112                 if (flags & FNM_IGNORECASE)
    2113                 {
    2114                     if (tolower(*mask) != tolower(*name))
    2115                         return FNM_NOMATCH;
    2116                 }
    2117                 else
    2118                 {
    2119                     if (*mask != *name)
    2120                         return FNM_NOMATCH;
    2121                 }
    2122                 ++mask;
    2123                 ++name;
    2124                 break;
    2125         }
    2126 }
    2127 
    2128 /*
    2129  * _fnmatch_unsigned:
    2130  *      Check whether the path name NAME matches the wildcard MASK.
    2131  *
    2132  *      Return:
    2133  *      --   0 (FNM_MATCH) if it matches,
    2134  *      --   _FNM_NOMATCH if it doesn't,
    2135  *      --   FNM_ERR on error.
    2136  *
    2137  *      The operation of this function is controlled by FLAGS.
    2138  *      This is an internal function, with unsigned arguments.
    2139  *
    2140  *      (c) 1994-1996 by Eberhard Mattes.
    2141  */
    2142 
    2143 static int _fnmatch_unsigned(const unsigned char *mask,
    2144                              const unsigned char *name,
    2145                              unsigned flags)
    2146 {
    2147     int     m_drive,
    2148             n_drive,
    2149             rc;
    2150 
    2151     /* Match and skip the drive name if present. */
    2152 
    2153     m_drive = ((isalpha(mask[0]) && mask[1] == ':') ? mask[0] : -1);
    2154     n_drive = ((isalpha(name[0]) && name[1] == ':') ? name[0] : -1);
    2155 
    2156     if (m_drive != n_drive)
    2157     {
    2158         if (m_drive == -1 || n_drive == -1)
    2159             return FNM_NOMATCH;
    2160         if (!(flags & FNM_IGNORECASE))
    2161             return FNM_NOMATCH;
    2162         if (tolower(m_drive) != tolower(n_drive))
    2163             return FNM_NOMATCH;
    2164     }
    2165 
    2166     if (m_drive != -1)
    2167         mask += 2;
    2168     if (n_drive != -1)
    2169         name += 2;
    2170 
    2171     /* Colons are not allowed in path names, except for the drive name,
    2172      * which was skipped above. */
    2173 
    2174     if (has_colon(mask) || has_colon(name))
    2175         return FNM_ERR;
    2176 
    2177     /* The name "\\server\path" should not be matched by mask
    2178      * "\*\server\path".  Ditto for /. */
    2179 
    2180     switch (flags & FNM_STYLE_MASK)
    2181     {
    2182         case FNM_OS2:
    2183         case FNM_DOS:
    2184 
    2185             if (IS_OS2_COMP_SEP(name[0]) && IS_OS2_COMP_SEP(name[1]))
    2186             {
    2187                 if (!(IS_OS2_COMP_SEP(mask[0]) && IS_OS2_COMP_SEP(mask[1])))
    2188                     return FNM_NOMATCH;
    2189                 name += 2;
    2190                 mask += 2;
    2191             }
    2192             break;
    2193 
    2194         case FNM_POSIX:
    2195 
    2196             if (name[0] == '/' && name[1] == '/')
    2197             {
    2198                 int             i;
    2199 
    2200                 name += 2;
    2201                 for (i = 0; i < 2; ++i)
    2202                     if (mask[0] == '/')
    2203                         ++mask;
    2204                     else if (mask[0] == '\\' && mask[1] == '/')
    2205                         mask += 2;
    2206                     else
    2207                         return FNM_NOMATCH;
    2208             }
    2209 
    2210             /* In Unix styles, treating ? and * w.r.t. components is simple.
    2211              * No need to do matching component by component. */
    2212 
    2213             return match_unix(mask, name, flags, name);
    2214     }
    2215 
    2216     /* Now compare all the components of the path name, one by one.
    2217      * Note that the path separator must not be enclosed in brackets. */
    2218 
    2219     while (*mask != 0 || *name != 0)
    2220     {
    2221 
    2222         /* If _FNM_PATHPREFIX is set, the names match if the end of MASK
    2223          * is reached even if there are components left in NAME. */
    2224 
    2225         if (*mask == 0 && (flags & FNM_PATHPREFIX))
    2226             return FNM_MATCH;
    2227 
    2228         /* Compare a single component of the path name. */
    2229 
    2230         rc = match_comp(mask, name, flags);
    2231         if (rc != FNM_MATCH)
    2232             return rc;
    2233 
    2234         /* Skip to the next component or to the end of the path name. */
    2235 
    2236         mask = skip_comp_os2(mask);
    2237         name = skip_comp_os2(name);
    2238     }
    2239 
    2240     /* If we reached the ends of both strings, the names match. */
    2241 
    2242     if (*mask == 0 && *name == 0)
    2243         return FNM_MATCH;
    2244 
    2245     /* The names do not match. */
    2246 
    2247     return FNM_NOMATCH;
    2248 }
    2249 
    2250 /*
    2251  *@@ strhMatchOS2:
    2252  *      this matches wildcards, similar to what DosEditName does.
    2253  *      However, this does not require a file to be present, but
    2254  *      works on strings only.
    2255  */
    2256 
    2257 BOOL strhMatchOS2(const char *pcszMask,     // in: mask (e.g. "*.txt")
    2258                   const char *pcszName)     // in: string to check (e.g. "test.txt")
    2259 {
    2260     return ((BOOL)(_fnmatch_unsigned((const unsigned char *)pcszMask,
    2261                                      (const unsigned char *)pcszName,
    2262                                      FNM_OS2 | FNM_IGNORECASE)
    2263                    == FNM_MATCH)
    2264            );
    2265 }
    2266 
    2267 /*
    2268  *@@ strhMatchExt:
    2269  *      like strhMatchOS2, but this takes all the flags
    2270  *      for input.
    2271  *
    2272  *@@added V0.9.15 (2001-09-14) [umoeller]
    2273  */
    2274 
    2275 BOOL strhMatchExt(const char *pcszMask,     // in: mask (e.g. "*.txt")
    2276                   const char *pcszName,     // in: string to check (e.g. "test.txt")
    2277                   unsigned flags)           // in: FNM_* flags
    2278 {
    2279     return ((BOOL)(_fnmatch_unsigned((const unsigned char *)pcszMask,
    2280                                      (const unsigned char *)pcszName,
    2281                                      flags)
    2282                    == FNM_MATCH)
    2283            );
    2284 }
    2285 
    2286 /* ******************************************************************
    2287  *
    22881663 *   Fast string searches
    22891664 *
Note: See TracChangeset for help on using the changeset viewer.