homework-jianmu/deps/MsvcLibX/src/fnmatch.c

125 lines
5.2 KiB
C

/*****************************************************************************\
* *
* Filename: fnmatch.c *
* *
* Description: DOS/WIN32 port of standard C library's fnmatch() *
* *
* Notes: TO DO: Manage FNM_PATHNAME, FNM_PERIOD, FNM_LEADING_DIR. *
* *
* History: *
* 2012-01-17 JFL Created this file. *
* 2013-03-10 JFL In DOS/Windows, the pattern "*.*" actually means "*". *
* 2014-02-13 JFL Removed warnings. *
* 2014-02-14 JFL In DOS/Windows, the pattern "*." means no extension. *
* 2014-02-17 JFL Wildcards match the empty string. *
* 2014-02-20 JFL Fixed "*." pattern matching. *
* 2014-02-28 JFL Added support for UTF-8 pathnames. *
* 2014-03-05 JFL In debug mode, hide recursive calls. *
* *
* Copyright 2016 Hewlett Packard Enterprise Development LP *
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
\*****************************************************************************/
#define _UTF8_SOURCE /* Generate the UTF-8 version of routines */
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include "msvcFnmatch.h" /* Include our associated .h, in the same dir as this .c. Do not use <>. */
#include "msvcDebugm.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#pragma warning(disable:4706) /* Ignore the "assignment within conditional expression" warning */
int fnmatch(const char *pszPattern, const char *pszName, int iFlags) {
char cp, cn;
size_t l;
const char *pc;
int iErr;
DEBUG_CODE(
int iHideRecursions = FALSE;
)
DEBUG_ENTER(("fnmatch(\"%s\", \"%s\", 0x%x);\n", pszPattern, pszName, iFlags));
DEBUG_CODE(if(DEBUG_IS_ON() && !XDEBUG_IS_ON()) iHideRecursions = TRUE;)
/* Special case in DOS/Windows: "*.*" will actually match any name, even without a dot */
if (!strcmp(pszPattern, "*.*")) pszPattern = "*";
/* Special case in DOS/Windows: "anything." means anything without extension */
l = strlen(pszPattern);
if (l && (pszPattern[l-1] == '.')) {
int i;
int lName = (int)strlen(pszName);
/* First eliminate the case of forbidden extensions <==> A '.' anywhere before the last character */
for (i=0; i<(lName-1); i++) { /* Search for a '.' in the name */
if (pszName[i] == '.') RETURN_CONST_COMMENT(FNM_NOMATCH, ("Forbidden extension found\n"));
}
/* If the name doesn't end with a dot, Remove the pattern's trailing '.' */
if (lName && (pszName[lName-1] != '.')) {
char *pszPattern2;
pszPattern2 = _strdup(pszPattern);
pszPattern2[--l] = '\0';
/* Recursively do the pattern matching with the new pattern */
DEBUG_CODE(if (iHideRecursions) iDebug -= 1;)
iErr = fnmatch(pszPattern2, pszName, iFlags);
DEBUG_CODE(if (iHideRecursions) iDebug += 1;)
free(pszPattern2);
RETURN_INT(iErr);
}
}
for ( ; (cp = *pszPattern) && (cn = *pszName); pszPattern++, pszName++) {
XDEBUG_PRINTF(("// cp='%c' cn='%c'\n", cp, cn));
switch (cp) {
case '?':
if (cn == '.') RETURN_CONST_COMMENT(FNM_NOMATCH, ("? does not match a .\n"));
break; /* Anything else matches. Continue analysing the pattern. */
case '*':
cp = *(++pszPattern);
if (!cp) RETURN_CONST_COMMENT(FNM_MATCH, ("'*' matches whatever remains in the string\n"));
for ( ; cn = *pszName; pszName++) {
DEBUG_CODE(if (iHideRecursions) iDebug -= 1;)
iErr = fnmatch(pszPattern, pszName, iFlags);
DEBUG_CODE(if (iHideRecursions) iDebug += 1;)
if (iErr == FNM_MATCH) RETURN_CONST(FNM_MATCH);
}
RETURN_CONST_COMMENT(FNM_NOMATCH, ("No tail string matches the remainder of the pattern\n"));
default:
if (iFlags & FNM_CASEFOLD) {
cp = (char)toupper(cp);
cn = (char)toupper(cn);
}
if (cp != cn) RETURN_CONST_COMMENT(FNM_NOMATCH, ("Character mismatch\n"));
break; /* The character matches. Continue analysing the pattern. */
}
}
/* '*' and '?' match the empty string */
if (*pszPattern && !*pszName) {
int bOnlyWildCards = TRUE;
for (pc=pszPattern; cp=*pc; pc++) {
if ((cp != '*') && (cp != '?')) {
bOnlyWildCards = FALSE;
break;
}
}
if (bOnlyWildCards) {
RETURN_CONST_COMMENT(FNM_MATCH, ("WildCards match the empty string\n"));
}
}
/* Special case in DOS/Windows: trailing dot allowed in pattern */
if ((*pszPattern == '.') && (!*(pszPattern+1)) && (!*pszName)) RETURN_CONST_COMMENT(FNM_MATCH, ("trailing dot matches empty string\n"));
if (*pszPattern || *pszName) RETURN_CONST_COMMENT(FNM_NOMATCH, ("Something remains that did not match\n"));
RETURN_CONST_COMMENT(FNM_MATCH, ("Complete match\n"));
}
#pragma warning(default:4706)