xref: /netbsd-src/sys/lib/libkern/pmatch.c (revision 2f9c47fb218a751aef1919a8d9287a8c32acf17d)
1*2f9c47fbSgutteridge /*	$NetBSD: pmatch.c,v 1.9 2024/10/09 23:16:03 gutteridge Exp $	*/
216a9632eSchristos 
316a9632eSchristos /*-
416a9632eSchristos  * Copyright (c) 1980, 1991 The Regents of the University of California.
516a9632eSchristos  * All rights reserved.
616a9632eSchristos  *
716a9632eSchristos  * Redistribution and use in source and binary forms, with or without
816a9632eSchristos  * modification, are permitted provided that the following conditions
916a9632eSchristos  * are met:
1016a9632eSchristos  * 1. Redistributions of source code must retain the above copyright
1116a9632eSchristos  *    notice, this list of conditions and the following disclaimer.
1216a9632eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
1316a9632eSchristos  *    notice, this list of conditions and the following disclaimer in the
1416a9632eSchristos  *    documentation and/or other materials provided with the distribution.
15aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
1616a9632eSchristos  *    may be used to endorse or promote products derived from this software
1716a9632eSchristos  *    without specific prior written permission.
1816a9632eSchristos  *
1916a9632eSchristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2016a9632eSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2116a9632eSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2216a9632eSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2316a9632eSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2416a9632eSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2516a9632eSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2616a9632eSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2716a9632eSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2816a9632eSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2916a9632eSchristos  * SUCH DAMAGE.
3016a9632eSchristos  */
3116a9632eSchristos 
3216a9632eSchristos #include <sys/param.h>
332be6059bSthorpej 
342be6059bSthorpej /* So we can build this in userland for the tests in strlist.c */
352be6059bSthorpej #if defined(_KERNEL) || defined(_STANDALONE)
3616a9632eSchristos #include <lib/libkern/libkern.h>
372be6059bSthorpej #else
382be6059bSthorpej int pmatch(const char *, const char *, const char **);
392be6059bSthorpej #endif
402be6059bSthorpej 
4116a9632eSchristos /*
4216a9632eSchristos  * pmatch():
4316a9632eSchristos  *	Return 2 on exact match.
4416a9632eSchristos  *	Return 1 on substring match.
4516a9632eSchristos  *	Return 0 on no match.
4616a9632eSchristos  *	Return -1 on error.
4716a9632eSchristos  * *estr will point to the end of the longest exact or substring match.
4816a9632eSchristos  */
4916a9632eSchristos int
5082357f6dSdsl pmatch(const char *string, const char *pattern, const char **estr)
5116a9632eSchristos {
5216a9632eSchristos 	u_char stringc, patternc, rangec;
5316a9632eSchristos 	int match, negate_range;
54fe82005eSchristos 	const char *oestr, *pestr, *testr = NULL;
5516a9632eSchristos 
5616a9632eSchristos 	if (estr == NULL)
5716a9632eSchristos 		estr = &testr;
5816a9632eSchristos 
5916a9632eSchristos 	for (;; ++string) {
6016a9632eSchristos 		stringc = *string;
6116a9632eSchristos 		switch (patternc = *pattern++) {
6216a9632eSchristos 		case 0:
6316a9632eSchristos 			*estr = string;
6416a9632eSchristos 			return stringc == '\0' ? 2 : 1;
6516a9632eSchristos 		case '?':
6616a9632eSchristos 			if (stringc == '\0')
6716a9632eSchristos 				return 0;
6816a9632eSchristos 			*estr = string;
6916a9632eSchristos 			break;
7016a9632eSchristos 		case '*':
7116a9632eSchristos 			if (!*pattern) {
7216a9632eSchristos 				while (*string)
7316a9632eSchristos 					string++;
7416a9632eSchristos 				*estr = string;
7516a9632eSchristos 				return 2;
7616a9632eSchristos 			}
7716a9632eSchristos 			oestr = *estr;
7816a9632eSchristos 			pestr = NULL;
7916a9632eSchristos 
8016a9632eSchristos 			do {
8116a9632eSchristos 				switch (pmatch(string, pattern, estr)) {
8216a9632eSchristos 				case -1:
8316a9632eSchristos 					return -1;
8416a9632eSchristos 				case 0:
8516a9632eSchristos 					break;
8616a9632eSchristos 				case 1:
8716a9632eSchristos 					pestr = *estr;
8816a9632eSchristos 					break;
8916a9632eSchristos 				case 2:
9016a9632eSchristos 					return 2;
9116a9632eSchristos 				default:
9216a9632eSchristos 					return -1;
9316a9632eSchristos 				}
9416a9632eSchristos 				*estr = string;
9516a9632eSchristos 			}
9616a9632eSchristos 			while (*string++);
9716a9632eSchristos 
9816a9632eSchristos 			if (pestr) {
9916a9632eSchristos 				*estr = pestr;
10016a9632eSchristos 				return 1;
10116a9632eSchristos 			} else {
10216a9632eSchristos 				*estr = oestr;
10316a9632eSchristos 				return 0;
10416a9632eSchristos 			}
10516a9632eSchristos 
10616a9632eSchristos 		case '[':
10716a9632eSchristos 			match = 0;
10816a9632eSchristos 			if ((negate_range = (*pattern == '^')) != 0)
10916a9632eSchristos 				pattern++;
11016a9632eSchristos 			while ((rangec = *pattern++) != '\0') {
11116a9632eSchristos 				if (rangec == ']')
11216a9632eSchristos 					break;
11316a9632eSchristos 				if (match)
11416a9632eSchristos 					continue;
11516a9632eSchristos 				if (rangec == '-' && *(pattern - 2) != '[' &&
11616a9632eSchristos 				    *pattern != ']') {
11716a9632eSchristos 					match =
11816a9632eSchristos 					    stringc <= (u_char)*pattern &&
11916a9632eSchristos 					    (u_char)*(pattern - 2) <= stringc;
12016a9632eSchristos 					pattern++;
12116a9632eSchristos 				} else
12216a9632eSchristos 					match = (stringc == rangec);
12316a9632eSchristos 			}
12416a9632eSchristos 			if (rangec == 0)
12516a9632eSchristos 				return -1;
12616a9632eSchristos 			if (match == negate_range)
12716a9632eSchristos 				return 0;
12816a9632eSchristos 			*estr = string;
12916a9632eSchristos 			break;
13016a9632eSchristos 		default:
13116a9632eSchristos 			if (patternc != stringc)
13216a9632eSchristos 				return 0;
13316a9632eSchristos 			*estr = string;
13416a9632eSchristos 			break;
13516a9632eSchristos 		}
13616a9632eSchristos 	}
13716a9632eSchristos }
138