1N/A/*
1N/A * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A *
1N/A */
1N/A
1N/A#pragma ident "%Z%%M% %I% %E% SMI"
1N/A
1N/A#include <sm/gen.h>
1N/ASM_RCSID("@(#)$Id: match.c,v 1.8 2001/03/02 19:57:08 ca Exp $")
1N/A
1N/A#include <sm/string.h>
1N/A
1N/A/*
1N/A** SM_MATCH -- Match a character string against a glob pattern.
1N/A**
1N/A** Parameters:
1N/A** str -- string.
1N/A** par -- pattern to find in str.
1N/A**
1N/A** Returns:
1N/A** true on match, false on non-match.
1N/A**
1N/A** A pattern consists of normal characters, which match themselves,
1N/A** and meta-sequences. A * matches any sequence of characters.
1N/A** A ? matches any single character. A [ introduces a character class.
1N/A** A ] marks the end of a character class; if the ] is missing then
1N/A** the [ matches itself rather than introducing a character class.
1N/A** A character class matches any of the characters between the brackets.
1N/A** The range of characters from X to Y inclusive is written X-Y.
1N/A** If the first character after the [ is ! then the character class is
1N/A** complemented.
1N/A**
1N/A** To include a ] in a character class, make it the first character
1N/A** listed (after the !, if any). To include a -, make it the first
1N/A** character listed (after the !, if any) or the last character.
1N/A** It is impossible for a ] to be the final character in a range.
1N/A** For glob patterns that literally match "*", "?" or "[",
1N/A** use [*], [?] or [[].
1N/A*/
1N/A
1N/Abool
1N/Asm_match(str, pat)
1N/A const char *str;
1N/A const char *pat;
1N/A{
1N/A bool ccnot, ccmatch, ccfirst;
1N/A const char *ccstart;
1N/A char c, c2;
1N/A
1N/A for (;;)
1N/A {
1N/A switch (*pat)
1N/A {
1N/A case '\0':
1N/A return *str == '\0';
1N/A case '?':
1N/A if (*str == '\0')
1N/A return false;
1N/A ++pat;
1N/A ++str;
1N/A continue;
1N/A case '*':
1N/A ++pat;
1N/A if (*pat == '\0')
1N/A {
1N/A /* optimize case of trailing '*' */
1N/A return true;
1N/A }
1N/A for (;;)
1N/A {
1N/A if (sm_match(pat, str))
1N/A return true;
1N/A if (*str == '\0')
1N/A return false;
1N/A ++str;
1N/A }
1N/A /* NOTREACHED */
1N/A case '[':
1N/A ccstart = pat++;
1N/A ccnot = false;
1N/A if (*pat == '!')
1N/A {
1N/A ccnot = true;
1N/A ++pat;
1N/A }
1N/A ccmatch = false;
1N/A ccfirst = true;
1N/A for (;;)
1N/A {
1N/A if (*pat == '\0')
1N/A {
1N/A pat = ccstart;
1N/A goto defl;
1N/A }
1N/A if (*pat == ']' && !ccfirst)
1N/A break;
1N/A c = *pat++;
1N/A ccfirst = false;
1N/A if (*pat == '-' && pat[1] != ']')
1N/A {
1N/A ++pat;
1N/A if (*pat == '\0')
1N/A {
1N/A pat = ccstart;
1N/A goto defl;
1N/A }
1N/A c2 = *pat++;
1N/A if (*str >= c && *str <= c2)
1N/A ccmatch = true;
1N/A }
1N/A else
1N/A {
1N/A if (*str == c)
1N/A ccmatch = true;
1N/A }
1N/A }
1N/A if (ccmatch ^ ccnot)
1N/A {
1N/A ++pat;
1N/A ++str;
1N/A }
1N/A else
1N/A return false;
1N/A continue;
1N/A default:
1N/A defl:
1N/A if (*pat != *str)
1N/A return false;
1N/A ++pat;
1N/A ++str;
1N/A continue;
1N/A }
1N/A }
1N/A}