Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-imap/imap-match.c @ 956:26cafa3dc09c HEAD
minor optimization
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 12 Jan 2003 01:49:45 +0200 |
parents | fd8888f6f037 |
children | d28571e8c810 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen imap_match_init() logic originates from Cyrus, but the code is fully rewritten. */ #include "lib.h" #include "imap-match.h" #include <ctype.h> struct imap_match_glob { int inboxcase; const char *inboxcase_end; char sep_char; char mask[1]; }; /* name of "INBOX" - must not have repeated substrings */ static const char inbox[] = "INBOX"; #define INBOXLEN (sizeof(inbox) - 1) struct imap_match_glob *imap_match_init(const char *mask, int inboxcase, char separator) { struct imap_match_glob *glob; const char *p, *inboxp; char *dst; /* +1 from struct */ glob = t_malloc(sizeof(struct imap_match_glob) + strlen(mask)); glob->sep_char = separator; /* @UNSAFE: compress the mask */ dst = glob->mask; while (*mask != '\0') { if (*mask == '*' || *mask == '%') { /* remove duplicate hierarchy wildcards */ while (*mask == '%') mask++; /* "%*" -> "*" */ if (*mask == '*') { /* remove duplicate wildcards */ while (*mask == '*' || *mask == '%') mask++; *dst++ = '*'; } else { *dst++ = '%'; } } else { *dst++ = *mask++; } } *dst++ = '\0'; if (inboxcase) { /* check if we could be comparing INBOX. */ inboxp = inbox; glob->inboxcase = TRUE; for (p = glob->mask; *p != '\0' && *p != '*'; p++) { if (*p != '%') { inboxp = strchr(inboxp, i_toupper(*p)); if (inboxp == NULL) { glob->inboxcase = FALSE; break; } if (*++inboxp == '\0') { /* now check that it doesn't end with any invalid chars */ if (*++p == '%') p++; if (*p != '\0' && *p != '*' && *p != glob->sep_char) glob->inboxcase = FALSE; break; } } } if (glob->inboxcase && inboxp != NULL && *inboxp != '\0' && *p != '*' && (p != glob->mask && p[-1] == '%')) glob->inboxcase = FALSE; } return glob; } static inline int cmp_chr(const struct imap_match_glob *glob, const char *data, char maskchr) { return *data == maskchr || (glob->inboxcase_end != NULL && data < glob->inboxcase_end && i_toupper(*data) == i_toupper(maskchr)); } static int match_sub(const struct imap_match_glob *glob, const char **data_p, const char **mask_p) { const char *mask, *data; int ret, best_ret; data = *data_p; mask = *mask_p; while (*mask != '\0' && *mask != '*' && *mask != '%') { if (!cmp_chr(glob, data, *mask)) { return *data == '\0' && *mask == glob->sep_char ? 0 : -1; } data++; mask++; } best_ret = -1; while (*mask == '%') { mask++; if (*mask == '\0') { while (*data != '\0' && *data != glob->sep_char) data++; break; } while (*data != '\0') { if (cmp_chr(glob, data, *mask)) { ret = match_sub(glob, &data, &mask); if (ret > 0) break; if (ret == 0) best_ret = 0; } if (*data == glob->sep_char) break; data++; } } if (*mask != '*') { if (*data == '\0' && *mask != '\0') return *mask == glob->sep_char ? 0 : best_ret; if (*data != '\0') return best_ret; } *data_p = data; *mask_p = mask; return 1; } int imap_match(struct imap_match_glob *glob, const char *data) { const char *mask; int ret; if (glob->inboxcase && strncasecmp(data, inbox, INBOXLEN) == 0 && (data[INBOXLEN] == '\0' || data[INBOXLEN] == glob->sep_char)) glob->inboxcase_end = data + INBOXLEN; else glob->inboxcase_end = NULL; mask = glob->mask; if (*mask != '*') { if ((ret = match_sub(glob, &data, &mask)) <= 0) return ret; if (*mask == '\0') return 1; } while (*mask == '*') { mask++; if (*mask == '\0') return 1; while (*data != '\0') { if (cmp_chr(glob, data, *mask)) { if (match_sub(glob, &data, &mask) > 0) break; } data++; } } return *data == '\0' && *mask == '\0' ? 1 : 0; }