xref: /netbsd-src/sys/lib/libkern/pmatch.c (revision 2f9c47fb218a751aef1919a8d9287a8c32acf17d)
1 /*	$NetBSD: pmatch.c,v 1.9 2024/10/09 23:16:03 gutteridge Exp $	*/
2 
3 /*-
4  * Copyright (c) 1980, 1991 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 
34 /* So we can build this in userland for the tests in strlist.c */
35 #if defined(_KERNEL) || defined(_STANDALONE)
36 #include <lib/libkern/libkern.h>
37 #else
38 int pmatch(const char *, const char *, const char **);
39 #endif
40 
41 /*
42  * pmatch():
43  *	Return 2 on exact match.
44  *	Return 1 on substring match.
45  *	Return 0 on no match.
46  *	Return -1 on error.
47  * *estr will point to the end of the longest exact or substring match.
48  */
49 int
50 pmatch(const char *string, const char *pattern, const char **estr)
51 {
52 	u_char stringc, patternc, rangec;
53 	int match, negate_range;
54 	const char *oestr, *pestr, *testr = NULL;
55 
56 	if (estr == NULL)
57 		estr = &testr;
58 
59 	for (;; ++string) {
60 		stringc = *string;
61 		switch (patternc = *pattern++) {
62 		case 0:
63 			*estr = string;
64 			return stringc == '\0' ? 2 : 1;
65 		case '?':
66 			if (stringc == '\0')
67 				return 0;
68 			*estr = string;
69 			break;
70 		case '*':
71 			if (!*pattern) {
72 				while (*string)
73 					string++;
74 				*estr = string;
75 				return 2;
76 			}
77 			oestr = *estr;
78 			pestr = NULL;
79 
80 			do {
81 				switch (pmatch(string, pattern, estr)) {
82 				case -1:
83 					return -1;
84 				case 0:
85 					break;
86 				case 1:
87 					pestr = *estr;
88 					break;
89 				case 2:
90 					return 2;
91 				default:
92 					return -1;
93 				}
94 				*estr = string;
95 			}
96 			while (*string++);
97 
98 			if (pestr) {
99 				*estr = pestr;
100 				return 1;
101 			} else {
102 				*estr = oestr;
103 				return 0;
104 			}
105 
106 		case '[':
107 			match = 0;
108 			if ((negate_range = (*pattern == '^')) != 0)
109 				pattern++;
110 			while ((rangec = *pattern++) != '\0') {
111 				if (rangec == ']')
112 					break;
113 				if (match)
114 					continue;
115 				if (rangec == '-' && *(pattern - 2) != '[' &&
116 				    *pattern != ']') {
117 					match =
118 					    stringc <= (u_char)*pattern &&
119 					    (u_char)*(pattern - 2) <= stringc;
120 					pattern++;
121 				} else
122 					match = (stringc == rangec);
123 			}
124 			if (rangec == 0)
125 				return -1;
126 			if (match == negate_range)
127 				return 0;
128 			*estr = string;
129 			break;
130 		default:
131 			if (patternc != stringc)
132 				return 0;
133 			*estr = string;
134 			break;
135 		}
136 	}
137 }
138