/*********************************** * * * smatch string compare utility * * Written by Explorer_Bob. * * modified by Foxen * * * ***********************************/ #include <stdio.h> #include "config.h" #include "smatch.h" /* #include <pwd.h> */ static int cmatch(char *s1, int c1); static int wmatch(char *wlist, char **s2); static int smatch(char *s1, char *s2); char *cstrchr(char *s, int c); char *estrchr(char *s, int c, int e); int cstrcmp(char *s, char *t); int cstrncmp(char *s, char *t, int n); #ifdef STRSTR char *strstr(char *s1, char *s2); #endif int equalstr(char *s, char *t); extern const char *uppercase, *lowercase; #define DOWNCASE(x) (lowercase[x]) /* String handlers * Some of these are already present in most C libraries, but go by * different names or are not always there. Since they're small, TF * simply uses its own routines with non-standard but consistant naming. */ char *cstrchr(char *s, int c) { c = DOWNCASE(c); while (*s && DOWNCASE(*s) != c) s++; if (*s || !c) return s; else return NULL; } char *estrchr(char *s, int c, int e) { while (*s) { if (*s == c) break; if (*s == e) s++; if (*s) s++; } if (*s) return s; else return NULL; } #ifdef STRSTR char *strstr(s1, s2) register char *s1, *s2; { register char *temp = s1; int len = strlen(s2); while (temp = strchr(temp, *s2)) { if (!strncmp(temp, s2, len)) return temp; else temp++; } return NULL; } #endif int cstrcmp(s, t) register char *s, *t; { while (*s && *t && DOWNCASE(*s) == DOWNCASE(*t)) { s++; t++; } return (DOWNCASE(*s) - DOWNCASE(*t)); } int cstrncmp(s, t, n) register char *s, *t; int n; { for (; n && *s && *t && DOWNCASE(*s) == DOWNCASE(*t); s++, t++, n--); if (n <= 0) return 0; else return (DOWNCASE(*s) - DOWNCASE(*t)); } #define test(x) if (DOWNCASE(x) == c1) return truthval /* Watch if-else constructions */ static int cmatch(char *s1, int c1) { int truthval = FALSE; c1 = DOWNCASE(c1); if (*s1 == '^') { s1++; truthval = TRUE; } if (*s1 == '-') test(*s1++); while (*s1) { if (*s1 == '\\' && *(s1 + 1)) s1++; if (*s1 == '-') { char c, start = *(s1 - 1), end = *(s1 + 1); if (start > end) { test(*s1++); } else { for (c = start; c <= end; c++) test(c); s1 += 2; } } else test(*s1++); } return !truthval; } static int wmatch(wlist, s2) char *wlist; /* word list */ char **s2; /* buffer to match from */ { char *matchstr, /* which word to find */ *strend, /* end of current word from wlist */ *matchbuf, /* where to find from */ *bufend; /* end of match buffer */ int result = 1; /* intermediate result */ if (!wlist || !*s2) return 1; matchbuf = *s2; matchstr = wlist; bufend = strchr(matchbuf, ' '); if (bufend == NULL) *s2 += strlen(*s2); else { *s2 = bufend; *bufend = 0; } do { if ((strend = estrchr(matchstr, '|', '\\')) != NULL) *strend = '\0'; result = smatch(matchstr, matchbuf); if (strend != NULL) *strend++ = '|'; if (!result) break; } while ((matchstr = strend) != NULL); if (bufend != NULL) *bufend = ' '; return result; } static int smatch(s1, s2) char *s1, *s2; { char ch, *start = s2; while (*s1) { switch (*s1) { case '\\': s1++; if (DOWNCASE(*s1++) != DOWNCASE(*s2++)) return 1; break; case '?': if (!*s2++) return 1; s1++; break; case '*': while (*s1 == '*' || (*s1 == '?' && *s2++)) s1++; if (*s1 == '?') return 1; if (*s1 == '{') { if (s2 == start) if (!smatch(s1, s2)) return 0; while ((s2 = strchr(s2, ' ')) != NULL) if (!smatch(s1, ++s2)) return 0; return 1; } else if (*s1 == '[') { while (*s2) if (!smatch(s1, s2++)) return 0; return 1; } if (*s1 == '\\') ch = *(s1 + 1); else ch = *s1; while ((s2 = cstrchr(s2, ch)) != NULL) { if (!smatch(s1, s2)) return 0; s2++; } return 1; case '[': { char *end; int tmpflg; if (!(end = estrchr(s1, ']', '\\'))) { return 1; } *end = '\0'; tmpflg = cmatch(&s1[1], *s2++); *end = ']'; if (tmpflg) { return 1; } s1 = end + 1; } break; case '{': if (s2 != start && *(s2 - 1) != ' ') return 1; { char *end; int tmpflg = 0; if (s1[1] == '^') tmpflg = 1; if (!(end = estrchr(s1, '}', '\\'))) { return 1; } *end = '\0'; tmpflg -= (wmatch(&s1[tmpflg + 1], &s2)) ? 1 : 0; *end = '}'; if (tmpflg) { return 1; } s1 = end + 1; } break; default: if (DOWNCASE(*s1++) != DOWNCASE(*s2++)) return 1; break; } } return DOWNCASE(*s1) - DOWNCASE(*s2); } int equalstr(char *s, char *t) { return !smatch(s, t); }