2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: match.c,v 1.23 2006/05/25 01:47:12 johnfranks Exp $
29 * functions for checking and matching regular expressions
35 static int match_word(const char *glob, const char *word, const char separator);
43 static char errmsg[STR_SIZE];
45 if ((result = regcomp(®c, regex,
46 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
47 regerror(result, ®c, errmsg, SIZEOF(errmsg));
63 result = alloc(2*strlen(regex)+1);
65 for(i=0,j=0;i<strlen(regex);i++) {
66 if(!isalnum((int)regex[i]))
81 char errmsg[STR_SIZE];
83 if((result = regcomp(®c, regex,
84 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
85 regerror(result, ®c, errmsg, SIZEOF(errmsg));
86 error(_("regex \"%s\": %s"), regex, errmsg);
90 if((result = regexec(®c, str, 0, 0, 0)) != 0
91 && result != REG_NOMATCH) {
92 regerror(result, ®c, errmsg, SIZEOF(errmsg));
93 error(_("regex \"%s\": %s"), regex, errmsg);
109 char errmsg[STR_SIZE];
111 if((result = regcomp(®c, regex,
112 REG_EXTENDED|REG_NOSUB)) != 0) {
113 regerror(result, ®c, errmsg, SIZEOF(errmsg));
114 error(_("regex \"%s\": %s"), regex, errmsg);
118 if((result = regexec(®c, str, 0, 0, 0)) != 0
119 && result != REG_NOMATCH) {
120 regerror(result, ®c, errmsg, SIZEOF(errmsg));
121 error(_("regex \"%s\": %s"), regex, errmsg);
137 static char errmsg[STR_SIZE];
139 regex = glob_to_regex(glob);
140 if ((result = regcomp(®c, regex,
141 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
142 regerror(result, ®c, errmsg, SIZEOF(errmsg));
161 char errmsg[STR_SIZE];
163 regex = glob_to_regex(glob);
164 if((result = regcomp(®c, regex,
165 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
166 regerror(result, ®c, errmsg, SIZEOF(errmsg));
167 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
171 if((result = regexec(®c, str, 0, 0, 0)) != 0
172 && result != REG_NOMATCH) {
173 regerror(result, ®c, errmsg, SIZEOF(errmsg));
174 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
195 * Allocate an area to convert into. The worst case is a five to
199 regex = alloc(1 + len * 5 + 1 + 1);
208 * The following are given a leading backslash to protect them
209 * unless they already have a backslash:
213 * Put a leading ^ and trailing $ around the result. If the last
214 * non-escaped character is \ leave the $ off to cause a syntax
215 * error when the regex is compiled.
221 for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
222 if (last_ch == '\\') {
224 ch = '\0'; /* so last_ch != '\\' next time */
225 } else if (last_ch == '[' && ch == '!') {
227 } else if (ch == '\\') {
229 } else if (ch == '*' || ch == '?') {
252 if (last_ch != '\\') {
269 char errmsg[STR_SIZE];
271 regex = tar_to_regex(glob);
272 if((result = regcomp(®c, regex,
273 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
274 regerror(result, ®c, errmsg, SIZEOF(errmsg));
275 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
279 if((result = regexec(®c, str, 0, 0, 0)) != 0
280 && result != REG_NOMATCH) {
281 regerror(result, ®c, errmsg, SIZEOF(errmsg));
282 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
303 * Allocate an area to convert into. The worst case is a five to
307 regex = alloc(1 + len * 5 + 1 + 1);
316 * The following are given a leading backslash to protect them
317 * unless they already have a backslash:
321 * Put a leading ^ and trailing $ around the result. If the last
322 * non-escaped character is \ leave the $ off to cause a syntax
323 * error when the regex is compiled.
329 for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
330 if (last_ch == '\\') {
332 ch = '\0'; /* so last_ch != '\\' next time */
333 } else if (last_ch == '[' && ch == '!') {
335 } else if (ch == '\\') {
337 } else if (ch == '*') {
340 } else if (ch == '?') {
360 if (last_ch != '\\') {
373 const char separator)
388 lenword = strlen(word);
389 nword = (char *)alloc(lenword + 3);
393 if(lenword == 1 && *w == separator) {
402 if(*(r-1) != separator)
408 * Allocate an area to convert into. The worst case is a six to
412 regex = (char *)alloc(1 + len * 6 + 1 + 1 + 2 + 2);
414 nglob = stralloc(glob);
417 if((len == 1 && nglob[0] == separator) ||
418 (len == 2 && nglob[0] == '^' && nglob[1] == separator) ||
419 (len == 2 && nglob[0] == separator && nglob[1] == '$') ||
420 (len == 3 && nglob[0] == '^' && nglob[1] == separator &&
434 * * -> [^\separator]*
438 * The following are given a leading backslash to protect them
439 * unless they already have a backslash:
444 * non-escaped character is \ leave it to cause a syntax
445 * error when the regex is compiled.
450 *r++ = '\\'; /* escape the separator */
453 if(*g == separator) g++;
455 else if(*g != separator) {
456 *r++ = '\\'; /* add a leading \separator */
460 for (ch = *g++; ch != '\0'; last_ch = ch, ch = *g++) {
462 if (last_ch == '\\') {
464 ch = '\0'; /* so last_ch != '\\' next time */
465 } else if (last_ch == '[' && ch == '!') {
467 } else if (ch == '\\') {
469 } else if (ch == '*' || ch == '?') {
470 if(ch == '*' && next_ch == '*') {
484 } else if (ch == '$' && next_ch == '\0') {
485 if(last_ch != separator) {
490 } else if ( ch == '('
505 if(last_ch != '\\') {
506 if(last_ch != separator && last_ch != '$') {
508 *r++ = separator; /* add a trailing \separator */
514 i = match(regex,nword);
534 lglob = (char *)alloc(strlen(glob)+1);
537 *c++ = (char)tolower(*d++);
540 lhost = (char *)alloc(strlen(host)+1);
543 *c++ = (char)tolower(*d++);
546 i = match_word(lglob, lhost, (int)'.');
558 return match_word(glob, disk, '/');
566 if (!isdigit((int)*(str++)))
574 const char * dateexp,
575 const char * datestamp)
578 size_t len, len_suffix;
580 char firstdate[100], lastdate[100];
584 if(strlen(dateexp) >= 100 || strlen(dateexp) < 1) {
588 /* strip and ignore an initial "^" */
589 if(dateexp[0] == '^') {
590 strncpy(mydateexp, dateexp+1, sizeof(mydateexp)-1);
591 mydateexp[sizeof(mydateexp)-1] = '\0';
594 strncpy(mydateexp, dateexp, sizeof(mydateexp)-1);
595 mydateexp[sizeof(mydateexp)-1] = '\0';
598 if(mydateexp[strlen(mydateexp)-1] == '$') {
600 mydateexp[strlen(mydateexp)-1] = '\0'; /* strip the trailing $ */
605 /* a single dash represents a date range */
606 if((dash = strchr(mydateexp,'-'))) {
607 if(match_exact == 1 || strchr(dash+1, '-')) {
611 /* format: XXXYYYY-ZZZZ, indicating dates XXXYYYY to XXXZZZZ */
613 len = (size_t)(dash - mydateexp); /* length of XXXYYYY */
614 len_suffix = strlen(dash) - 1; /* length of ZZZZ */
615 if (len_suffix > len) goto illegal;
616 len_prefix = len - len_suffix; /* length of XXX */
620 strncpy(firstdate, mydateexp, len);
621 firstdate[len] = '\0';
622 strncpy(lastdate, mydateexp, len_prefix);
623 strncpy(&(lastdate[len_prefix]), dash, len_suffix);
624 lastdate[len] = '\0';
625 if (!alldigits(firstdate) || !alldigits(lastdate))
627 if (strncmp(firstdate, lastdate, strlen(firstdate)) > 0)
629 return ((strncmp(datestamp, firstdate, strlen(firstdate)) >= 0) &&
630 (strncmp(datestamp, lastdate , strlen(lastdate)) <= 0));
633 if (!alldigits(mydateexp))
635 if(match_exact == 1) {
636 return (strcmp(datestamp, mydateexp) == 0);
639 return (strncmp(datestamp, mydateexp, strlen(mydateexp)) == 0);
643 error(_("Illegal datestamp expression %s"),dateexp);
650 const char * levelexp,
654 size_t len, len_suffix;
656 char lowend[100], highend[100];
657 char mylevelexp[100];
660 if(strlen(levelexp) >= 100 || strlen(levelexp) < 1) {
661 error(_("Illegal level expression %s"),levelexp);
665 if(levelexp[0] == '^') {
666 strncpy(mylevelexp, levelexp+1, strlen(levelexp)-1);
667 mylevelexp[strlen(levelexp)-1] = '\0';
670 strncpy(mylevelexp, levelexp, strlen(levelexp));
671 mylevelexp[strlen(levelexp)] = '\0';
674 if(mylevelexp[strlen(mylevelexp)] == '$') {
676 mylevelexp[strlen(mylevelexp)] = '\0';
681 if((dash = strchr(mylevelexp,'-'))) {
682 if(match_exact == 1) {
683 error(_("Illegal level expression %s"),levelexp);
686 len = (size_t)(dash - mylevelexp);
687 len_suffix = strlen(dash) - 1;
688 len_prefix = len - len_suffix;
691 strncpy(lowend, mylevelexp, len);
693 strncpy(highend, mylevelexp, len_prefix);
694 strncpy(&(highend[len_prefix]), dash, len_suffix);
696 return ((strncmp(level, lowend, strlen(lowend)) >= 0) &&
697 (strncmp(level, highend , strlen(highend)) <= 0));
700 if(match_exact == 1) {
701 return (strcmp(level, mylevelexp) == 0);
704 return (strncmp(level, mylevelexp, strlen(mylevelexp)) == 0);