match.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * match.c
  3. * wildcard matching functions
  4. *
  5. *
  6. * Once this code was working, I added support for % so that I could
  7. * use the same code both in Eggdrop and in my IrcII client.
  8. * Pleased with this, I added the option of a fourth wildcard, ~,
  9. * which matches varying amounts of whitespace (at LEAST one space,
  10. * though, for sanity reasons).
  11. *
  12. * This code would not have been possible without the prior work and
  13. * suggestions of various sourced. Special thanks to Robey for
  14. * all his time/help tracking down bugs and his ever-helpful advice.
  15. *
  16. * 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
  17. *
  18. * Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
  19. * crf@cfox.bchs.uh.edu
  20. *
  21. * I hereby release this code into the public domain
  22. *
  23. */
  24. #include "main.h"
  25. #define QUOTE '\\' /* quoting character (overrides wildcards) */
  26. #define WILDS '*' /* matches 0 or more characters (including spaces) */
  27. #define WILDP '%' /* matches 0 or more non-space characters */
  28. #define WILDQ '?' /* matches ecactly one character */
  29. #define WILDT '~' /* matches 1 or more spaces */
  30. #define NOMATCH 0
  31. #define MATCH (match+sofar)
  32. #define PERMATCH (match+saved+sofar)
  33. int _wild_match_per(register unsigned char *m, register unsigned char *n)
  34. {
  35. unsigned char *ma = m, *lsm = 0, *lsn = 0, *lpm = 0, *lpn = 0;
  36. int match = 1, saved = 0, space;
  37. register unsigned int sofar = 0;
  38. /* null strings should never match */
  39. if ((m == 0) || (n == 0) || (!*n))
  40. return NOMATCH;
  41. while (*n) {
  42. if (*m == WILDT) { /* Match >=1 space */
  43. space = 0; /* Don't need any spaces */
  44. do {
  45. m++;
  46. space++;
  47. } /* Tally 1 more space ... */
  48. while ((*m == WILDT) || (*m == ' ')); /* for each space or ~ */
  49. sofar += space; /* Each counts as exact */
  50. while (*n == ' ') {
  51. n++;
  52. space--;
  53. } /* Do we have enough? */
  54. if (space <= 0)
  55. continue; /* Had enough spaces! */
  56. }
  57. /* Do the fallback */
  58. else {
  59. switch (*m) {
  60. case 0:
  61. do
  62. m--; /* Search backwards */
  63. while ((m > ma) && (*m == '?')); /* For first non-? char */
  64. if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
  65. return PERMATCH; /* nonquoted * = match */
  66. break;
  67. case WILDP:
  68. while (*(++m) == WILDP); /* Zap redundant %s */
  69. if (*m != WILDS) { /* Don't both if next=* */
  70. if (*n != ' ') { /* WILDS can't match ' ' */
  71. lpm = m;
  72. lpn = n; /* Save '%' fallback spot */
  73. saved += sofar;
  74. sofar = 0; /* And save tally count */
  75. }
  76. continue; /* Done with '%' */
  77. }
  78. /* FALL THROUGH */
  79. case WILDS:
  80. do
  81. m++; /* Zap redundant wilds */
  82. while ((*m == WILDS) || (*m == WILDP));
  83. lsm = m;
  84. lsn = n;
  85. lpm = 0; /* Save '*' fallback spot */
  86. match += (saved + sofar); /* Save tally count */
  87. saved = sofar = 0;
  88. continue; /* Done with '*' */
  89. case WILDQ:
  90. m++;
  91. n++;
  92. continue; /* Match one char */
  93. case QUOTE:
  94. m++; /* Handle quoting */
  95. }
  96. if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching */
  97. m++;
  98. n++;
  99. sofar++;
  100. continue; /* Tally the match */
  101. }
  102. #ifdef WILDT
  103. }
  104. #endif
  105. if (lpm) { /* Try to fallback on '%' */
  106. n = ++lpn;
  107. m = lpm;
  108. sofar = 0; /* Restore position */
  109. if ((*n | 32) == 32)
  110. lpm = 0; /* Can't match 0 or ' ' */
  111. continue; /* Next char, please */
  112. }
  113. if (lsm) { /* Try to fallback on '*' */
  114. n = ++lsn;
  115. m = lsm; /* Restore position */
  116. saved = sofar = 0;
  117. continue; /* Next char, please */
  118. }
  119. return NOMATCH; /* No fallbacks=No match */
  120. }
  121. while ((*m == WILDS) || (*m == WILDP))
  122. m++; /* Zap leftover %s & *s */
  123. return (*m) ? NOMATCH : PERMATCH; /* End of both = match */
  124. }
  125. int _wild_match(register unsigned char *m, register unsigned char *n)
  126. {
  127. unsigned char *ma = m, *na = n, *lsm = 0, *lsn = 0;
  128. int match = 1;
  129. register int sofar = 0;
  130. /* null strings should never match */
  131. if ((ma == 0) || (na == 0) || (!*ma) || (!*na))
  132. return NOMATCH;
  133. /* find the end of each string */
  134. while (*(++m));
  135. m--;
  136. while (*(++n));
  137. n--;
  138. while (n >= na) {
  139. switch (*m) {
  140. case WILDS: /* Matches anything */
  141. do
  142. m--; /* Zap redundant wilds */
  143. while ((m >= ma) && (*m == WILDS));
  144. lsm = m;
  145. lsn = n;
  146. match += sofar;
  147. sofar = 0; /* Update fallback pos */
  148. continue; /* Next char, please */
  149. case WILDQ:
  150. m--;
  151. n--;
  152. continue; /* '?' always matches */
  153. }
  154. if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching char */
  155. m--;
  156. n--;
  157. sofar++; /* Tally the match */
  158. continue; /* Next char, please */
  159. }
  160. if (lsm) { /* To to fallback on '*' */
  161. n = --lsn;
  162. m = lsm;
  163. if (n < na)
  164. lsm = 0; /* Rewind to saved pos */
  165. sofar = 0;
  166. continue; /* Next char, please */
  167. }
  168. return NOMATCH; /* No fallback=No match */
  169. }
  170. while ((m >= ma) && (*m == WILDS))
  171. m--; /* Zap leftover %s & *s */
  172. return (m >= ma) ? NOMATCH : MATCH; /* Start of both = match */
  173. }