2 * This program is copyright Alec Muffett 1993. The author disclaims all
3 * responsibility or liability with respect to it's usage or its effect
4 * upon hardware or computer systems, and maintains copyright as set out
5 * in the "LICENCE" document which accompanies distributions of Crack v4.0
9 static char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
20 Debug(val, a, b, c, d, e, f, g)
22 char *a, *b, *c, *d, *e, *f, *g;
24 fprintf(stderr, a, b, c, d, e, f);
30 #define RULE_PREPEND '^'
31 #define RULE_APPEND '$'
32 #define RULE_REVERSE 'r'
33 #define RULE_UPPERCASE 'u'
34 #define RULE_LOWERCASE 'l'
35 #define RULE_PLURALISE 'p'
36 #define RULE_CAPITALISE 'c'
37 #define RULE_DUPLICATE 'd'
38 #define RULE_REFLECT 'f'
39 #define RULE_SUBSTITUTE 's'
40 #define RULE_MATCH '/'
44 #define RULE_EXTRACT 'x'
45 #define RULE_OVERSTRIKE 'o'
46 #define RULE_INSERT 'i'
47 #define RULE_EQUALS '='
48 #define RULE_PURGE '@'
49 #define RULE_CLASS '?' /* class rule? socialist ethic in cracker? */
51 #define RULE_DFIRST '['
52 #define RULE_DLAST ']'
54 #define RULE_MFIRST '('
55 #define RULE_MLAST ')'
58 Suffix(myword, suffix)
69 return (STRCMP((myword + i - j), suffix));
77 Reverse(str) /* return a pointer to a reversal */
82 static char area[STRINGSIZE];
93 Uppercase(str) /* return a pointer to an uppercase */
97 static char area[STRINGSIZE];
101 *(ptr++) = CRACK_TOUPPER(*str);
110 Lowercase(str) /* return a pointer to an lowercase */
114 static char area[STRINGSIZE];
118 *(ptr++) = CRACK_TOLOWER(*str);
127 Capitalise(str) /* return a pointer to an capitalised */
131 static char area[STRINGSIZE];
136 *(ptr++) = CRACK_TOLOWER(*str);
141 area[0] = CRACK_TOUPPER(area[0]);
146 Pluralise(string) /* returns a pointer to a plural */
147 register char *string;
150 static char area[STRINGSIZE];
151 length = strlen(string);
152 strcpy(area, string);
154 if (!Suffix(string, "ch") ||
155 !Suffix(string, "ex") ||
156 !Suffix(string, "ix") ||
157 !Suffix(string, "sh") ||
158 !Suffix(string, "ss"))
160 /* bench -> benches */
162 } else if (length > 2 && string[length - 1] == 'y')
164 if (strchr("aeiou", string[length - 2]))
166 /* alloy -> alloys */
170 /* gully -> gullies */
171 strcpy(area + length - 1, "ies");
173 } else if (string[length - 1] == 's')
187 Substitute(string, old, new) /* returns pointer to a swapped about copy */
188 register char *string;
193 static char area[STRINGSIZE];
197 *(ptr++) = (*string == old ? new : *string);
205 Purge(string, target) /* returns pointer to a purged copy */
206 register char *string;
207 register char target;
210 static char area[STRINGSIZE];
214 if (*string != target)
223 /* -------- CHARACTER CLASSES START HERE -------- */
226 * this function takes two inputs, a class identifier and a character, and
227 * returns non-null if the given character is a member of the class, based
228 * upon restrictions set out below
232 MatchClass(class, input)
244 case '?': /* ?? -> ? */
251 /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
254 case 'v': /* vowels */
255 c = CRACK_TOLOWER(input);
256 if (strchr("aeiou", c))
263 case 'c': /* consonants */
264 c = CRACK_TOLOWER(input);
265 if (strchr("bcdfghjklmnpqrstvwxyz", c))
272 case 'w': /* whitespace */
273 if (strchr("\t ", input))
280 case 'p': /* punctuation */
281 if (strchr(".`,:;'!?\"", input))
288 case 's': /* symbols */
289 if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input))
295 /* LOGICAL GROUPINGS */
298 case 'l': /* lowercase */
306 case 'u': /* uppercase */
314 case 'a': /* alphabetic */
322 case 'x': /* alphanumeric */
330 case 'd': /* digits */
338 Debug(1, "MatchClass: unknown class %c\n", class);
351 PolyStrchr(string, class)
352 register char *string;
357 if (MatchClass(class, *string))
367 PolySubst(string, class, new) /* returns pointer to a swapped about copy */
368 register char *string;
373 static char area[STRINGSIZE];
377 *(ptr++) = (MatchClass(class, *string) ? new : *string);
385 PolyPurge(string, class) /* returns pointer to a purged copy */
386 register char *string;
390 static char area[STRINGSIZE];
394 if (!MatchClass(class, *string))
403 /* -------- BACK TO NORMALITY -------- */
409 if (isdigit(character))
411 return (character - '0');
412 } else if (islower(character))
414 return (character - 'a' + 10);
415 } else if (isupper(character))
417 return (character - 'A' + 10);
423 Mangle(input, control) /* returns a pointer to a controlled Mangle */
427 int limit,min_to_shift;
430 static char area[STRINGSIZE];
431 char area2[STRINGSIZE];
437 min_to_shift = (j+1)/2 ;
443 if ( min_to_shift > 5 )
446 for (ptr = control; *ptr; ptr++)
453 strcpy(area, Reverse(area));
456 strcpy(area, Uppercase(area));
459 strcpy(area, Lowercase(area));
461 case RULE_CAPITALISE:
462 strcpy(area, Capitalise(area));
465 strcpy(area, Pluralise(area));
468 strcat(area, Reverse(area));
477 Debug(1, "Mangle: '>' missing argument in '%s'\n", control);
481 limit = Char2Int(*(++ptr));
484 Debug(1, "Mangle: '>' weird argument in '%s'\n", control);
487 if (strlen(area) <= limit)
496 Debug(1, "Mangle: '<' missing argument in '%s'\n", control);
500 limit = Char2Int(*(++ptr));
503 Debug(1, "Mangle: '<' weird argument in '%s'\n", control);
506 if (strlen(area) >= limit)
515 Debug(1, "Mangle: prepend missing argument in '%s'\n", control);
520 strcpy(area2 + 1, area);
527 Debug(1, "Mangle: append missing argument in '%s'\n", control);
531 register char *string;
534 string[-1] = *(++ptr);
539 if (!ptr[1] || !ptr[2])
541 Debug(1, "Mangle: extract missing argument in '%s'\n", control);
548 start = Char2Int(*(++ptr));
549 length = Char2Int(*(++ptr));
550 if (start < 0 || length < 0)
552 Debug(1, "Mangle: extract: weird argument in '%s'\n", control);
556 for (i = 0; length-- && area2[start + i]; i++)
558 area[i] = area2[start + i];
560 /* cant use strncpy() - no trailing NUL */
564 case RULE_OVERSTRIKE:
565 if (!ptr[1] || !ptr[2])
567 Debug(1, "Mangle: overstrike missing argument in '%s'\n", control);
572 i = Char2Int(*(++ptr));
575 Debug(1, "Mangle: overstrike weird argument in '%s'\n",
589 if (!ptr[1] || !ptr[2])
591 Debug(1, "Mangle: insert missing argument in '%s'\n", control);
598 i = Char2Int(*(++ptr));
601 Debug(1, "Mangle: insert weird argument in '%s'\n",
617 /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
619 case RULE_PURGE: /* @x or @?c */
620 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
622 Debug(1, "Mangle: delete missing arguments in '%s'\n", control);
624 } else if (ptr[1] != RULE_CLASS)
626 strcpy(area, Purge(area, *(++ptr)));
629 strcpy(area, PolyPurge(area, ptr[2]));
633 case RULE_SUBSTITUTE: /* sxy || s?cy */
634 if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
636 Debug(1, "Mangle: subst missing argument in '%s'\n", control);
638 } else if (ptr[1] != RULE_CLASS)
640 strcpy(area, Substitute(area, ptr[1], ptr[2]));
644 strcpy(area, PolySubst(area, ptr[2], ptr[3]));
648 case RULE_MATCH: /* /x || /?c */
649 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
651 Debug(1, "Mangle: '/' missing argument in '%s'\n", control);
653 } else if (ptr[1] != RULE_CLASS)
655 if (!strchr(area, *(++ptr)))
661 if (!PolyStrchr(area, ptr[2]))
668 case RULE_NOT: /* !x || !?c */
669 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
671 Debug(1, "Mangle: '!' missing argument in '%s'\n", control);
673 } else if (ptr[1] != RULE_CLASS)
675 if (strchr(area, *(++ptr)))
681 if (PolyStrchr(area, ptr[2]))
689 * alternative use for a boomerang, number 1: a standard throwing
690 * boomerang is an ideal thing to use to tuck the sheets under
691 * the mattress when making your bed. The streamlined shape of
692 * the boomerang allows it to slip easily 'twixt mattress and
693 * bedframe, and it's curve makes it very easy to hook sheets
697 case RULE_EQUALS: /* =nx || =n?c */
698 if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
700 Debug(1, "Mangle: '=' missing argument in '%s'\n", control);
705 if ((i = Char2Int(ptr[1])) < 0)
707 Debug(1, "Mangle: '=' weird argument in '%s'\n", control);
710 if (ptr[2] != RULE_CLASS)
720 if (!MatchClass(*ptr, area[i]))
731 if (strlen(area) > min_to_shift ) {
733 for (i = 1; area[i] ; i++)
735 area[i - 1] = area[i];
745 if ( strlen(area) > min_to_shift ) {
747 for (i = 1; area[i] ; i++);
754 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
756 Debug(1, "Mangle: '(' missing argument in '%s'\n", control);
760 if (ptr[1] != RULE_CLASS)
770 if (!MatchClass(*ptr, area[0]))
777 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
779 Debug(1, "Mangle: ')' missing argument in '%s'\n", control);
785 for (i = 0; area[i]; i++);
795 if (ptr[1] != RULE_CLASS)
805 if (!MatchClass(*ptr, area[i]))
813 Debug(1, "Mangle: unknown command %c in %s\n", *ptr, control);
818 if (!area[0]) /* have we deweted de poor widdle fing away? */
826 PMatch(control, string)
827 register char *control;
828 register char *string;
830 while (*string && *control)
832 if (!MatchClass(*control, *string))
841 if (*string || *control)