mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-16 12:30:13 +01:00
292 lines
8.3 KiB
C++
292 lines
8.3 KiB
C++
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/* *
|
|
*
|
|
*
|
|
* shexp.c: shell-like wildcard match routines
|
|
*
|
|
* See shexp.h for public documentation.
|
|
*
|
|
* Rob McCool
|
|
*
|
|
*/
|
|
|
|
#include "nsWildCard.h"
|
|
#include "plstr.h"
|
|
#include "prmem.h"
|
|
|
|
/* ----------------------------- shexp_valid ------------------------------ */
|
|
|
|
|
|
static int
|
|
_valid_subexp(char *expr, char stop)
|
|
{
|
|
register int x,y,t;
|
|
int nsc,np,tld;
|
|
|
|
x=0;nsc=0;tld=0;
|
|
|
|
while(expr[x] && (expr[x] != stop)) {
|
|
switch(expr[x]) {
|
|
case '~':
|
|
if(tld) return INVALID_SXP;
|
|
else ++tld;
|
|
case '*':
|
|
case '?':
|
|
case '^':
|
|
case '$':
|
|
++nsc;
|
|
break;
|
|
case '[':
|
|
++nsc;
|
|
if((!expr[++x]) || (expr[x] == ']'))
|
|
return INVALID_SXP;
|
|
for(++x;expr[x] && (expr[x] != ']');++x)
|
|
if(expr[x] == '\\')
|
|
if(!expr[++x])
|
|
return INVALID_SXP;
|
|
if(!expr[x])
|
|
return INVALID_SXP;
|
|
break;
|
|
case '(':
|
|
++nsc;np = 0;
|
|
while(1) {
|
|
if(expr[++x] == ')')
|
|
return INVALID_SXP;
|
|
for(y=x;(expr[y]) && (expr[y] != '|') && (expr[y] != ')');++y)
|
|
if(expr[y] == '\\')
|
|
if(!expr[++y])
|
|
return INVALID_SXP;
|
|
if(!expr[y])
|
|
return INVALID_SXP;
|
|
if(expr[y] == '|')
|
|
++np;
|
|
t = _valid_subexp(&expr[x],expr[y]);
|
|
if(t == INVALID_SXP)
|
|
return INVALID_SXP;
|
|
x+=t;
|
|
if(expr[x] == ')') {
|
|
if(!np)
|
|
return INVALID_SXP;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case ')':
|
|
case ']':
|
|
return INVALID_SXP;
|
|
case '\\':
|
|
if(!expr[++x])
|
|
return INVALID_SXP;
|
|
default:
|
|
break;
|
|
}
|
|
++x;
|
|
}
|
|
if((!stop) && (!nsc))
|
|
return NON_SXP;
|
|
return ((expr[x] == stop) ? x : INVALID_SXP);
|
|
}
|
|
|
|
int
|
|
NS_WildCardValid(char *expr)
|
|
{
|
|
int x;
|
|
|
|
x = _valid_subexp(expr, '\0');
|
|
return (x < 0 ? x : VALID_SXP);
|
|
}
|
|
|
|
|
|
/* ----------------------------- shexp_match ----------------------------- */
|
|
|
|
|
|
#define MATCH 0
|
|
#define NOMATCH 1
|
|
#define ABORTED -1
|
|
|
|
static int _shexp_match(char *str, char *expr, PRBool case_insensitive);
|
|
|
|
static int
|
|
_handle_union(char *str, char *expr, PRBool case_insensitive)
|
|
{
|
|
char *e2 = (char *) PR_Malloc(sizeof(char)*strlen(expr));
|
|
register int t,p2,p1 = 1;
|
|
int cp;
|
|
|
|
while(1) {
|
|
for(cp=1;expr[cp] != ')';cp++)
|
|
if(expr[cp] == '\\')
|
|
++cp;
|
|
for(p2 = 0;(expr[p1] != '|') && (p1 != cp);p1++,p2++) {
|
|
if(expr[p1] == '\\')
|
|
e2[p2++] = expr[p1++];
|
|
e2[p2] = expr[p1];
|
|
}
|
|
for (t=cp+1; ((e2[p2] = expr[t]) != 0); ++t,++p2) {}
|
|
if(_shexp_match(str,e2, case_insensitive) == MATCH) {
|
|
PR_Free(e2);
|
|
return MATCH;
|
|
}
|
|
if(p1 == cp) {
|
|
PR_Free(e2);
|
|
return NOMATCH;
|
|
}
|
|
else ++p1;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
_shexp_match(char *str, char *expr, PRBool case_insensitive)
|
|
{
|
|
register int x,y;
|
|
int ret,neg;
|
|
|
|
ret = 0;
|
|
for(x=0,y=0;expr[y];++y,++x) {
|
|
if((!str[x]) && (expr[y] != '(') && (expr[y] != '$') && (expr[y] != '*'))
|
|
ret = ABORTED;
|
|
else {
|
|
switch(expr[y]) {
|
|
case '$':
|
|
if( (str[x]) )
|
|
ret = NOMATCH;
|
|
else
|
|
--x; /* we don't want loop to increment x */
|
|
break;
|
|
case '*':
|
|
while(expr[++y] == '*'){}
|
|
if(!expr[y])
|
|
return MATCH;
|
|
while(str[x]) {
|
|
switch(_shexp_match(&str[x++],&expr[y], case_insensitive)) {
|
|
case NOMATCH:
|
|
continue;
|
|
case ABORTED:
|
|
ret = ABORTED;
|
|
break;
|
|
default:
|
|
return MATCH;
|
|
}
|
|
break;
|
|
}
|
|
if((expr[y] == '$') && (expr[y+1] == '\0') && (!str[x]))
|
|
return MATCH;
|
|
else
|
|
ret = ABORTED;
|
|
break;
|
|
case '[':
|
|
neg = ((expr[++y] == '^') && (expr[y+1] != ']'));
|
|
if (neg)
|
|
++y;
|
|
|
|
if ((isalnum(expr[y])) && (expr[y+1] == '-') &&
|
|
(isalnum(expr[y+2])) && (expr[y+3] == ']'))
|
|
{
|
|
int start = expr[y], end = expr[y+2];
|
|
|
|
/* Droolproofing for pinheads not included */
|
|
if(neg ^ ((str[x] < start) || (str[x] > end))) {
|
|
ret = NOMATCH;
|
|
break;
|
|
}
|
|
y+=3;
|
|
}
|
|
else {
|
|
int matched;
|
|
|
|
for (matched=0;expr[y] != ']';y++)
|
|
matched |= (str[x] == expr[y]);
|
|
if (neg ^ (!matched))
|
|
ret = NOMATCH;
|
|
}
|
|
break;
|
|
case '(':
|
|
return _handle_union(&str[x],&expr[y], case_insensitive);
|
|
break;
|
|
case '?':
|
|
break;
|
|
case '\\':
|
|
++y;
|
|
default:
|
|
if(case_insensitive)
|
|
{
|
|
if(toupper(str[x]) != toupper(expr[y]))
|
|
ret = NOMATCH;
|
|
}
|
|
else
|
|
{
|
|
if(str[x] != expr[y])
|
|
ret = NOMATCH;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if(ret)
|
|
break;
|
|
}
|
|
return (ret ? ret : (str[x] ? NOMATCH : MATCH));
|
|
}
|
|
|
|
int
|
|
NS_WildCardMatch(char *str, char *xp, PRBool case_insensitive) {
|
|
register int x;
|
|
char *expr = PL_strdup(xp);
|
|
|
|
if(!expr)
|
|
return 1;
|
|
|
|
for(x=strlen(expr)-1;x;--x) {
|
|
if((expr[x] == '~') && (expr[x-1] != '\\')) {
|
|
expr[x] = '\0';
|
|
if(_shexp_match(str,&expr[++x], case_insensitive) == MATCH)
|
|
goto punt;
|
|
break;
|
|
}
|
|
}
|
|
if(_shexp_match(str,expr, case_insensitive) == MATCH) {
|
|
PR_Free(expr);
|
|
return 0;
|
|
}
|
|
|
|
punt:
|
|
PR_Free(expr);
|
|
return 1;
|
|
}
|