源码下载地址如下:

http://web.mit.edu/freebsd/csup/fnmatch.h

http://web.mit.edu/freebsd/csup/fnmatch.c

代码整体不错,但是中有一些地方稍有不足。我没有去改(添加了一些{},以便结构清晰)。

  1. /*
  2. * Copyright (c) 1989, 1993, 1994
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Guido van Rossum.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. All advertising materials mentioning features or use of this software
  17. * must display the following acknowledgement:
  18. * This product includes software developed by the University of
  19. * California, Berkeley and its contributors.
  20. * 4. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. *
  36. * From FreeBSD fnmatch.c 1.11
  37. * $Id: fnmatch.c,v 1.3 1997/08/19 02:34:30 jdp Exp $
  38. */
  39. #ifndef _FNMATCH_H_
  40. #define _FNMATCH_H_
  41. #define FNM_NOMATCH 1 /* Match failed. */
  42. #define FNM_NOESCAPE 0x01 /* 禁用反斜杠进行转义 */
  43. #define FNM_PATHNAME 0x02 /* 斜杠只能被斜杠匹配(即不能被*或者?匹配) */
  44. #define FNM_PERIOD 0x04 /* Period must be matched by period. */
  45. /*如果这个标志设置了,string 里的起始点号必须匹配 pattern 里的点号。
  46. 一个点号被认为是起始点号,如果它是string 第一个字符,或者如果同时设
  47. 置了 FNM_PATHNAME,紧跟在斜杠后面的点号。
  48. */
  49. #define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
  50. /*如果这个标志(GNU 扩展)设置了,模式必须匹配跟随在斜杠之后的 string
  51. 的初始片断。这个标志主要是给 glibc 内部使用并且只在一定条件下实现。
  52. 即只匹配目录路径部分,不匹配到具体文件名
  53. */
  54. #define FNM_CASEFOLD 0x10 /* 模式匹配忽略大小写. */
  55. #define FNM_PREFIX_DIRS 0x20 /* Directory prefixes of pattern match too. */
  56. /* Make this compile successfully with "gcc -traditional" */
  57. #ifndef __STDC__
  58. #define const /* empty */
  59. #endif
  60. int fnmatch(const char *, const char *, int);
  61. #endif /* !_FNMATCH_H_ */
  62. #if defined(LIBC_SCCS) && !defined(lint)
  63. static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
  64. #endif /* LIBC_SCCS and not lint */
  65. /*
  66. * 函数fnmatch(),如POSIX 1003.2-1992 B.6节所述。
  67. * 将文件名或者目录名与pattern进行比较
  68. */
  69. #include <ctype.h>
  70. #include <string.h>
  71. #include <stdio.h>
  72. // 定义字符串结尾标志
  73. #define EOS '\0'
  74. static const char *rangematch(const char *, char, int);
  75. int
  76. fnmatch(const char *pattern, const char *string, int flags)
  77. {
  78. const char *stringstart;
  79. char c, test;
  80. for (stringstart = string;;){
  81. // 逐个取匹配字符串中的成分(分为*?和range三种)
  82. switch (c = *pattern++) {
  83. case EOS: // 没有匹配串的情况
  84. // 如果忽略'/'后面的部分,则匹配成功
  85. if ((flags & FNM_LEADING_DIR) && *string == '/'){
  86. return (0);
  87. }
  88. // 如果string也是空串,则匹配成功
  89. return (*string == EOS ? 0 : FNM_NOMATCH);
  90. case '?': // 匹配单个任意字符
  91. // string为空则不能匹配
  92. if (*string == EOS){
  93. return (FNM_NOMATCH);
  94. }
  95. // 判断'/'是否只能由'/'进行匹配
  96. if (*string == '/' && (flags & FNM_PATHNAME)){
  97. return (FNM_NOMATCH);
  98. }
  99. // 判断是否string中的起始'.'必须匹配pattern中的'.'(即'?'不能匹配'.')
  100. if (*string == '.' && (flags & FNM_PERIOD) &&
  101. (string == stringstart ||
  102. ((flags & FNM_PATHNAME) && *(string - 1) == '/'))){
  103. return (FNM_NOMATCH);
  104. }
  105. // 匹配成功则匹配string的下一个字符
  106. ++string;
  107. break;
  108. case '*': // 匹配单个或多个任意字符
  109. c = *pattern;
  110. /* 多个'*'当做一个 */
  111. while (c == '*'){
  112. c = *++pattern;
  113. }
  114. // 判断是否需要对'.'进行处理
  115. if (*string == '.' && (flags & FNM_PERIOD) &&
  116. (string == stringstart ||
  117. ((flags & FNM_PATHNAME) && *(string - 1) == '/'))){
  118. return (FNM_NOMATCH);
  119. }
  120. /* 优化 * 在匹配串结尾或者在 /. 之前的匹配*/
  121. if (c == EOS){ // 在结尾
  122. // 判断 * 是否不匹配斜杠
  123. if (flags & FNM_PATHNAME){
  124. // 不匹配斜杠,则判断是否忽略'/'之后部分
  125. return ((flags & FNM_LEADING_DIR) ||
  126. ((strchr(string, '/') == NULL) ? 0 : FNM_NOMATCH));
  127. }else{
  128. return (0);
  129. }
  130. }
  131. else if (c == '/' && flags & FNM_PATHNAME) { // 在 /. 之前
  132. // 如果string后没有 '/'则匹配失败
  133. if ((string = strchr(string, '/')) == NULL){
  134. return (FNM_NOMATCH);
  135. }
  136. break;
  137. }
  138. /* 非特殊情况下,递归匹配 */
  139. while ((test = *string) != EOS) {
  140. // 不对'.'进行特殊处理,进行匹配(则只需判断'/'匹配情况)
  141. if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)){
  142. return (0); // 匹配成功
  143. }
  144. // 对 '/'进行处理(斜杠只匹配斜杠,则匹配失败)
  145. if (test == '/' && flags & FNM_PATHNAME){
  146. break;
  147. }
  148. ++string;
  149. }
  150. // 返回匹配失败(即*没有匹配成功,'.'和'/'上的匹配没有成功)
  151. return (FNM_NOMATCH);
  152. case '[': // range 范围匹配
  153. if (*string == EOS){
  154. return (FNM_NOMATCH); // 空串匹配失败
  155. }
  156. if (*string == '/' && flags & FNM_PATHNAME){
  157. return (FNM_NOMATCH); // '/'匹配失败
  158. }
  159. if ((pattern =
  160. rangematch(pattern, *string, flags)) == NULL){
  161. return (FNM_NOMATCH); // 范围匹配失败
  162. }
  163. ++string;
  164. break;
  165. case '\\': // 斜杠匹配(判断是否需要转义)
  166. if (!(flags & FNM_NOESCAPE)) {
  167. if ((c = *pattern++) == EOS) {
  168. c = '\\';
  169. --pattern;
  170. }
  171. }
  172. /* 非上述部分,则直接匹配单个字符 */
  173. default:
  174. if (c == *string){
  175. ; // 直接匹配上了
  176. }else if ((flags & FNM_CASEFOLD) &&
  177. (tolower((unsigned char)c) ==
  178. tolower((unsigned char)*string))){
  179. ; // 忽略大小写匹配成功
  180. }
  181. else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
  182. ((c == '/' && string != stringstart) ||
  183. (string == stringstart + 1 && *stringstart == '/'))){
  184. return (0); // 匹配成功
  185. }
  186. else{
  187. return (FNM_NOMATCH); // 匹配失败
  188. }
  189. string++;
  190. break;
  191. }
  192. }
  193. /* NOTREACHED */
  194. }
  195. // 字符范围匹配
  196. // pattern传入如 [a-x]*** 形式的字符串
  197. // 匹配失败或匹配到EOS结束(也是失败),返回NULL
  198. // 成功返回匹配串的下一个匹配成分首地址
  199. static const char *
  200. rangematch(const char *pattern, char test, int flags)
  201. {
  202. // 此处没有对c进行初始化,可能出问题(栈上变量默认值未定)
  203. int negate, ok;
  204. char c, c2;
  205. /*
  206. * A bracket expression starting with an unquoted circumflex
  207. * character produces unspecified results
  208. * 以无引号 ^ 字符开始的方括号表达式,将产生未指定的结果
  209. * (IEEE 1003.2-1992,3.13.2). 此实现将其视为 '!',以与正则表达式语法保持一致.
  210. * J.T. Conklin (conklin@ngai.kaleida.com)
  211. */
  212. // 检测方括号表达式中第一个字符
  213. // 如果为!或者^,则对后面匹配的结果取反
  214. if ((negate = (*pattern == '!' || *pattern == '^'))){
  215. ++pattern;
  216. }
  217. // 忽略大小写,则转为小写处理
  218. if (flags & FNM_CASEFOLD){
  219. test = tolower((unsigned char)test);
  220. }
  221. // 循环到方括号表达式结束
  222. for (ok = 0; (c = *pattern++) != ']';) {
  223. // 如果没有禁用转义,获取字符
  224. if (c == '\\' && !(flags & FNM_NOESCAPE)){
  225. c = *pattern++;
  226. }
  227. // 匹配结束
  228. if (c == EOS){
  229. return (NULL);
  230. }
  231. // 忽略大小写,则转为小写
  232. if (flags & FNM_CASEFOLD){
  233. c = tolower((unsigned char)c);
  234. }
  235. // 如果当前匹配项c 的下一个是'-',则获取'-'后面的一个字符
  236. // 例如,匹配串为 [a-x] 当前c为a,则c2为x,表示匹配a-x之间字符
  237. if (*pattern == '-'
  238. && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
  239. pattern += 2;
  240. // 判断是否需要转义
  241. if (c2 == '\\' && !(flags & FNM_NOESCAPE)){
  242. c2 = *pattern++;
  243. }
  244. if (c2 == EOS){
  245. return (NULL);
  246. }
  247. // 判断是否区分大小写
  248. if (flags & FNM_CASEFOLD){
  249. c2 = tolower((unsigned char)c2);
  250. }
  251. // 判断test是否位于 [c,c2]区间
  252. if ((unsigned char)c <= (unsigned char)test &&
  253. (unsigned char)test <= (unsigned char)c2){
  254. ok = 1;
  255. }
  256. }
  257. else if (c == test){
  258. ok = 1;
  259. }
  260. }
  261. // 返回匹配结果
  262. return (ok == negate ? NULL : pattern);
  263. }

fnmatch源码阅读的更多相关文章

  1. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  2. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  3. 【原】FMDB源码阅读(一)

    [原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...

  4. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  5. 【原】AFNetworking源码阅读(五)

    [原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...

  6. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

  7. 【原】AFNetworking源码阅读(三)

    [原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...

  8. 【原】AFNetworking源码阅读(二)

    [原]AFNetworking源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中我们在iOS Example代码中提到了AFHTTPSessionMa ...

  9. 【原】AFNetworking源码阅读(一)

    [原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...

随机推荐

  1. [转]如何在本地apache上架设多个站点

    http://dongxin1390008.blog.163.com/blog/static/3179247820094279581256/ 通常情况下,我们有时候需要架设多个站点 比如 我的web站 ...

  2. PO BO VO DTO POJO DAO概念及其作用(附转换图)

    J2EE开发中大量的专业缩略语很是让人迷惑,尤其是跟一些高手讨论问题的时候,三分钟就被人家满口的专业术语喷晕了,PO VO BO DTO POJO DAO,一大堆的就来了(听过老罗对这种现象的批判的朋 ...

  3. 使用C++ Builder XE5获取Sensor值之Light Sensor

    献上代码C++代码,仅供參考. 若使用Delphi.请參考文献,http://blogs.embarcadero.com/davidi/2013/12/02/43032/ 一定记得要安装FireMon ...

  4. 奇怪吸引子---Bouali

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  5. C语言中将0到1000的浮点数用强制指针类型转换的方式生成一幅图像

    搞过计算机图像的人都知道,图像中的每一个像素通常为一个整型数,它可以分成4个无符号的char类型,以表示其RGBA四个分量.一幅图像可以看做是一个二维整型数组.这里我会生成一个float数组,其数组大 ...

  6. C/C++ 指针函数 与 函数指针

    指针函数是个函数,是返回指针类型到函数. 函数指针是个指针,是指向函数地址到指针. 区分两者的关键点是,函数名是否用*和括号“包围”起来. #include <stdio.h> int * ...

  7. go语言之进阶篇字符串操作常用函数介绍

    下面这些函数来自于strings包,这里介绍一些我平常经常用到的函数,更详细的请参考官方的文档. 一.字符串操作常用函数介绍 1.Contains func Contains(s, substr st ...

  8. 硬链接(hard link)和符号连接(symbolic link)

    inode ====== 在Linux系统中,内核为每一个新创建的文件分配一个inode,每个文件都有一个惟一的inode号,我们可以将inode简单理解成一个指针,它永远指向本文件的具体存储位置.文 ...

  9. Binary Tree Level Order Traversal II leetcode java

    题目: Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from ...

  10. 简短介绍 C# 6 的新特性

    几周前我在不同的地方读到了有关C#6的一些新特性.我就决定把它们都收集到一起,如果你还没有读过,就可以一次性把它们都过一遍.它们中的一些可能不会如预期那样神奇,但那也只是目前的更新. 你可以通过下载V ...